Java基础
Java学习的正确打开方式
学习是一个过程,是一个不断累积、不断沉淀、不断总结、善于传达自己的个人见解以及乐于分享的过程。
链接:https://blog.csdn.net/qq_44543508/article/details/102651841
这个博主写的很好,从入门到进阶,框架学习和现在流行的技术,学习的大方向。
狂神说基础,参考博客(看视频讲的细,就是太慢了)
小橘子ღ(UI好看,右侧悬浮导航栏) 南北tp 每天进步一丶丶
1.Saas
Software-as-a-Service的缩写名称,软件即服务,通过网络提供软件服务。
2.Java学习路线和时间安排
3.C&C++
1972年C诞生,贴合硬件,运行极快,效率极高。操作系统,编译器,数据库,网络系统等,指针和内存管理。
1982年C++诞生,面对对象,兼容C,图形领域、游戏等。
4.Java初生
1995年的网页简单儿粗糙,缺乏互动性。
图形界面的程序(Applet)。
Java 2 标准版(J2SE):去占领桌面,
Java 2 移动版(J2Me):占领手机,
Java 2 企业版(J2EE):占领服务器。
大量的巨头加入。
5.Java发展
构件工具:Ant,Maven,Jekins
应用服务器:Tomcat,Jetty,Jboss,Websphere,weblogic
Web开发:Struts,spring,Hibernate,MyBatis
开发工具:Eclipse,Netbean,intellij Idea,Jbuilder
2006:Hadoop(大数据领域) 2008:Android(手机端)
6.Java特性和优势
简单性,面向对象,可移植性,高性能,分布式,动态性,多线程,安全性,健壮性
三高:高可用,高性能,高并发。
分布式:一个业务拆分成多个子业务,部署在不同的服务器上,每个子系统被称为“服务”,这些子系统能够独立运行在web容器中,它们之间通过RPC方式通信。
集群:同一个业务,部署在多个服务器上。
7.JDK、JRE、JVM
JDK:Java Development Kit Java开发工具(开发人员使用),JRE+Java开发工具。
JRE:Java Runtime Environment Java运行环境(运行Java程序),JVM+Java语言的核心类库。
JVM:Java Virtual Machine Java虚拟机
JDK包含JRE,JDK和JRE都包含JVM。
8.冯.诺依曼体系结构
DOS(Disk Operating System):磁盘操作系统
cmd C:命令行打开c盘,dir显示目录下的文件
9.程序运行机制
1.新建hello.java文件 2.编写代码 3.编译 javac hello.java 生成一个class文件
4.运行class文件,javac hello(不加.class)
编译型
通过编译器(compiler)将源代码编译成机器码, 一般需经过编译(compile)、链接(linker)这两个步骤。
编译是把源代码编译成机器码,链接是把各个模块的机器码和依赖库串连起来生成可执行文件。
优点: 执行效率高。可以脱离语言环境独立运行。
缺点: 修改后需要重新编译。移植性差。
代表语言:C、C++、Pascal、Object-C
解释型
使用专门的解释器对源程序逐行解释成特定平台的机器码并立即执行。
优点: 移植性强,只要平台提供相应的解释器,就可以运行源代码。
缺点:每次运行都需要将源代码解释称机器码并执行,效率较低;
代表语言: JavaScript、Python、PHP、Perl、Ruby
混合型
既然编译型和解释型各有缺点就会有人想到把两种类型整合起来,取其精华去其糟粕。就出现了半编译型语言。比如C#,C#在编译的时候不是直接编译成机器码而是中间码,.NET平台提供了中间语言运行库运行中间码,中间语言运行库类似于Java虚拟机。.net在编译成IL代码后,保存在dll中,首次运行时由JIT在编译成机器码缓存在内存中,下次直接执行(博友回复指出)。微软政策限制了C#的推广,C#不开源。
Java生成字节码再在Java虚拟机中解释执行。
严格来说混合型语言属于解释型语言。C#更接近编译型语言。
动态语言和静态语言
动态类型语言和静态类型语言
强类型语言和弱类型语言
链接:https://www.cnblogs.com/1101-/p/12836787.html#683668352
10.注释,标识符,关键字,数据类型,类型转化,变量,运算符,包机制,javadoc,开发手册
链接:https://www.cnblogs.com/1101-/p/12836871.html
11.Java数据类型 int
四类八种:整数型,浮点型,字符型,布尔型.
bsil fd char boolean
++ ++ |
自增(前):先运算后取值 自增(后):先取值后运算 |
a=2;b=++a; a=2;b=a++; |
a=3;b=3 a=3;b=2 |
---|---|---|---|
- - - - |
自减(前):先运算后取值 自减(后):先取值后运算 |
a=2;b=- -a a=2;b=a- - |
a=1;b=1 a=1;b=2 |
int i1 = 10;int i2 = 20; int i = i1++; System.out.print(“i=”+i); System.out.println(“i1=”+i1); i = ++i1; System.out.print(“i=”+i); System.out.println(“i1=”+i1); i = i2--; System.out.print(“i=”+i); System.out.println(“i2=”+i2); i = --i2; System.out.print(“i=”+i); System.out.println(“i2=”+i2); 输出: i=10 i1=11 i=12 i1=12 i=20 i2= 19 i=18 i2=18
“&”和“&&”的区别:
单&时,左边无论真假,右边都进行运算;
双&时,如果左边为真,右边参与运算,如果左边为假,那么右边不参与运算。
//&”和“&&”的区别 // int x = 1; // int y=1; ////f&t // if(x++ == 2 & ++y == 2){ // x =7; // } //// x=2 ,y=2 // System.out.println("x=" + x + " ,y="+y); int x = 1,y = 1; //f&&t if(x++==2 && ++y==2){ x =7; } System.out.println("x="+x+",y="+y);
“|”和“||”的区别同理,||表示:当左边为真,右边不参与运算。
// int x = 1,y = 1; ////t |f // if(x++==1 | ++y==1){ // x =7; // } // //x=7,y=2 // System.out.println("x="+x+",y="+y); int x = 1,y = 1; if(x++==1 || ++y==1){ x =7; } //x=7,y=1 System.out.println("x="+x+",y="+y);
将数值123.5678四舍五入保留两 位小数
//将数值123.5678四舍五入保留两 位小数 double a =123.5678; System.out.println(a); a*=100; a+=0.5; System.out.println(a); int b= (int) a; System.out.println(b); double c=(double) b/100; System.out.println(c); System.out.println("-----------"); System.out.println(String.format("%.2f ", 123.5678));
// int a = 10; // int b = 20; // int c= 0; // c=a/b; // // c=0 // System.out.println(c); //------------------------ // double a = 10; // int b = 20; // double c= 0; // c=a/b; // // c=0.5 // System.out.println(c); //------------------------ // 二进制BIN 0b 八进制OCT 0 十进制DEC 十六进制HEX 0x int i2 = 010; int i3 = 0x11; // i2八进制10,二进制1000,十进制和十六进制都是8 System.out.println(i2); /*转换成二进制之后各位相或 * 1000 | 0011 = 1011 0x1011为11 * */ System.out.println(i2|3); /*0x11 0b00001 0001 17 * 十六进制的11,转化为二进制00001 0001,二进制转化为十进制等于17 * */ System.out.println(i3);
12.Scanner 类
import java.util.Scanner; Scanner s=new Scanner(System.in);//创建扫描器对象,用于接受键盘数据 if(s.hasNext()){ String str=s.next(); System.out.println(str); } s.close();//凡是属于IO流的类如果不关闭会一直占用资源,用完要关闭
next():有效字符之前的空白自动去掉,之后的空白作为分隔符或结束符
nextLine():以Enter作为结束符
s.hasNextInt(); 一次执行后退出
13.流程控制
if(){} if(){} else if(){} else{} switch(expression){//变量类型byte,short,int,char. //JavaSE7后支持String。对应为s.hashCode() //标签必须是字符串常量或字面量 ? case value: break; default: } //没有break,会穿透,执行后面不匹配的标签内代码 while(){} do { //代码语句 }while(布尔表达式); break continue outer: goto outer;
14.方法
菜鸟教程 Java 测验五(函数)
class Main { public static void main(String[] args) { String str = "runoob"; str.toUpperCase(); str += "wwwrunoobcom"; //r unoob wwwru noobc om //str.substring(x, y) 返回 ‘x'(包含) 到 ‘y'(不包含) 位置的字符串 String string = str.substring(2,13);//noob wwwru no //str.charAt(4);为o string = string + str.charAt(4); //输出结果为noobwwwrunoo System.out.println(string); }
1、方法的重载
-
重载就是在一个类中,有相同的函数名称,但形参不同的函数;
-
方法的重载规则:
- 方法名称必须相同;
- 参数列表必须不同(个数不同、或类型不同、参数排列顺序不同等)
- 方法的返回类型也可以相同也可以不同
- 仅仅返回类型不同不足以成为方法的重载
-
实现原理
方法名称相同时,汇编器会根据调用方法的参数个数、参数类型等去逐个匹配,以选择对应的方法,如果匹配失败,则编译器报错。
2、可变参数
- 从JDK1.5开始,Java支持传递同类型的可变参数给一个方法。
- 在方法声明中,在指定参数类型后加一个省略号(…)。
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。
public static void printMax(double... numbers){ if(numbers.length==0){ System.out.println("No argument passed"); return; } double result = numbers[0]; for(int i = 1; i < numbers.length; i++){ if (numbers[i] > result){ result = numbers[i]; } } System.out.println("The max value is " + result); } 123456789101112131415
3、递归
递归就是:A方法调用A方法,就是自己调用自己。
递归结构包括两个部分:
- 递归头:什么时候不调用自身方法。如果没有头,将陷入死循环。 - 什么时候需要调用自身方法。 12 // 递归思想 public class RecursiveTest { public static void main(String[] args) { int result = f(5); System.out.println(result); } // 利用递归求阶乘 public static int f(int num){ if (num==1){ return num; }else { return num*f(num - 1); } } }
Java使用栈机制,占用内存较高。
15.数组
1、声明和创建
int[] nums = new int[10]; //1.声明一个数组 int[] nums; //2.创建一个数组 nums = new int[10]; 12345
2、三种初始化方式
-
静态初始化
//静态初始化:创建 + 赋值 int[] a = {1,2,3,4,5}; 12 -
动态初始化
//动态初始化:包含默认初始化 int[] b = new int[10]; b[0] = 10; 123 -
默认初始化
数组是引用类型,它的元素相当于类的实例变量,因此数组一经分配空间,其中的每个元素也被按照实例变量同样的方式被隐式初始化。
3、冒泡排序
思路:大数往后沉 / 小数往后移
import java.util.Arrays; public class Demo01 { // 冒泡排序 public static void main(String[] args) { // 1.比较数组中,两个相邻的元素,如果第一个比第二个大,我们就交换他们的位置 // 2.每一次比较,都会产生一个最大或最小的数字 // 3.下一轮,则可以少一次排序 // 4.依次循环,直到结束 int[] arr = { 7, 40, 12, 74, 8, 90 }; System.out.println(arr.length); int[] a = sort(arr); System.out.println(Arrays.toString(a)); } public static int[] sort(int[] array) { // 临时变量 int temp = 0; // 外层循环,判断我们这个要走多少次; for(int i = 0; i < array.length; i++) { boolean flag = false; // 内层循环,比较判断两个数,如果第一个数比第二个数大,则交换位置 for(int j = 0; j < array.length - 1 - i; j++) { if(array[j] > array[j + 1]) { //如果第一个数大于第二个数,2>1,第二个数放前,第一个数放后。 temp = array[j]; array[j] = array[j + 1]; array[j + 1] = temp; flag = true; } } if(flag == false) { break; } } return array; } }
4、稀疏数组
-
当一个数组中大部分元素为0,或者为同一值得数组时,可以使用稀疏数组来保存该数组。
-
稀疏数组的处理方式是:
-
记录数组一共有几行几列,有多少不同值;
-
把具有不同值得元素和行列及值记录在一个小规模数组中,从而缩小程序的规模;
import java.util.Arrays; public class Demo02 { // 稀疏数组 public static void main(String[] args) { // 1.创建一个二维数组11*11, 0:没有棋子,1:黑棋,2白棋 int[][] array1 = new int[11][11]; array1[1][2] = 1; array1[2][3] = 2; // 输出原始的数组 System.out.println("输出原始的数组"); for(int[] ints: array1) { for(int anInt: ints) { System.out.print(anInt + "\t"); } System.out.println(); } System.out.println("============"); // 转换为稀疏数组保存 // 获取有效的个数 int sum = 0; for(int i = 0; i < 11; i++) { for(int j = 0; j < 11; j++) { if(array1[i][j] != 0) { sum++; } } } System.out.println("有效值的个数:" + sum); // 2.创建一个稀疏数组 int[][] array2 = new int[sum + 1][3]; /*sum+1,三行两个有效数字, 第一列第一个数存横坐标, 第二列第二个数存纵坐标, 第三列第三个数存有效个数*/ array2[0][0] = 11; array2[0][1] = 11; array2[0][2] = sum; // 遍历二维数组,将非零的值存放到稀疏数组中 int count = 0; for(int i = 0; i < array1.length; i++) { for(int j = 0; j < array1[i].length; j++) { if(array1[i][j] != 0) { count++; array2[count][0] = i; array2[count][1] = j; array2[count][2] = array1[i][j]; } } } // 输出稀疏数组 System.out.println("稀疏数组"); for(int i = 0; i < array2.length; i++) { System.out.println(array2[i][0] + "\t" + array2[i][1] + "\t" + array2[i][2] + "\t"); } System.out.println("==================="); System.out.println("还原数组"); // 1.读取稀疏数组,十一行十一列 int[][] array3 = new int[array2[0][0]][array2[0][1]]; // 2.给其中的元素还原它的值 for(int i = 1; i < array2.length; i++) { array3[array2[i][0]][array2[i][1]] = array2[i][2]; // array3[array2[i][0]][array2[i][1]]还原横纵坐标 // array2[i][2]; 坐标的值 } // 输出还原后的数组 System.out.println("输出还原后的数组"); for(int[] ints: array3) { for(int anInt: ints) { System.out.print(anInt + "\t"); } System.out.println(); } } } Java实现八大排序算法
-
16.面向对象编程
面向对象01:什么是面向对象
面向过程思想:步骤清晰简单,第一步做什么,第二步做什么;处理较为简单的问题。
面向对象思想:物以类聚,分类的思维模式,思考问题首先解决问题会需要哪些分类,然后对这些分类进行单独思考。最后,才对某个分类下的细节进行面向对象的思索。
适合处理复杂的问题,适合处理需要多人协作的问题。
OOP(Object Oriented Programming)
面向对象编程的本质:以类的方式组织代码,以对象的组织(封装)数据。
三大特性:封装,继承,多态。抽象
面向对象 02:回顾方法的定义
break:跳出switch循环,结束循环。continue:结束依次循环。return:方法结束,返回类型和返回值相同。
方法名:见名知意,驼峰命名法。参数列表:(参数类型,参数名),...可变参数,数组运用可变参数。
面向对象03:回顾方法的调用
静态方法:
public static void say(){ system.out.print("1111"); }//可直接通过方法名调用,和类一起加载。
非静态方法:
public void say(){ system.out.print("1111"); } //调用 Student student = new Student();//实例化这个类new,对象类型 对象名 =对象值; student.say();
形参:
public static int add(int a,int b){//int a,int b,形参 return a+b; }
实参:
public static void main(String[] args){ int add = Demo03.add(1,3);//1,3;实参 System.out.println(add); }
值传递:
a=10,返回值为空,a的值还为1。
引用传递:
面向对象04:类与对象的创建
没有study方法的输出。
面向对象05:构造器详解
有参构造器:一旦定义了有参构造,无参构造必须显示定义。
无参构造器:使用new关键字,本质是在调用构造器;初始化值。
面向对象06:创建对象内存分析
OOM(OutOfMemory)产生的过程
栈Stack:
-
栈描述的是方法执行的内存模型、每个方法被调用都会传建一个栈帧(储存局部变量、操作数、方法出口等)。
-
栈是每一个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)。
-
线程私有,不能实现线程之间的共享。
-
栈的存储特性: 先进后出。
-
由系统自动分配,速度快,一个连续的内存空间。
-
一切new出来的对象,类的非静态成员变量.
-
分为三部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
堆heap:
-
怼用来储存创建好的对象和数组(数组也是对象)。
-
JVM只有一个堆,被线程所共享。
-
一个不连续的内存空间,分配灵活,速度慢。
-
基本数据类型,对象的引用。
方法区method:
-
JVM只有一个方法区,被所有线程共享。
-
方法区实际也是堆,只适用于存储类、常量相关的信息。
-
存储class二进制文件,包含虚拟机加载的类信息、class类对象、常量、静态变量、即时编译后的代码等数据。
-
static修饰的变量与方法。
-
常量池是方法区的一部分内存,常量池在编译期间就将一部分数据存放在该区域,包含基本数据类型如int、long等以final声明的常量值。
-
串池也是方法区中的一部分内存,用于存放string字符串,对于方法运行期位于栈中的局部变量string变量的值可以通过string.intern()方法将该值置入到变量池中。
-
方法区是线程安全的,由于所有的线程都共享方法区,所以,方法去里的数据访问必须被设计成线程安全的。方法区的静态变量一个线程访问的时候另一个线程必须等待。
队列(FIFO先进先出):
队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
面向对象07:简单小结类与对象
面向对象08:封装详解
面向对象09:什么是继承
ctrl+h看类的关系,所有的类都默认的或间接继承Object
面向对象10:Super详解
super注意点:
- super调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中!
- super和this 不能同时调用构造方法!
Vs this:
代表的对象不同:
this:本身调用者这个对象
super:代表父类 对象的应用
前提
this:没有继承也可以使用
super:只能在继承条件才可以使用
构造方法
this() ;本类的构造
super():父类的构造!
面向对象11:方法重写
重写:需要有继承关系,子类重写父类的方法!
1.方法名必须相同
2.参数列表必须相同.
3.修饰符:范围可以扩大但不能缩小: public>Protected>Default>private
4.抛出的异常:范围,可以被缩小,但不能扩大: ClassNotFoundException --> Exception(大)
重写,子类的方法和父类必要一致: 方法体不同!
为什么需要重写:
1.父类的功能,子类不“定需要, 或者不一定满足!
Alt + Insert ; override;
子类重写父类,执行子类方法。
面向对象12:什么是多态
多态注意事项:
-
多态是方法的多态,属性没有多态
-
父类和子类,有联系 类型转换异常!ClassCastException!
-
存在条件:继承关系,方法需要重写,父类引用指向子类对象! Father f1 = new Son();
不符合多态:static 方法,属于类,不属于实例;final常量;private方法。
面向对象13:instanceof和类型转换
类型转化:父子之间,子类转换为父类,可能丢失自己本来的一些方法!
父类引用指向子类的对象;向上转型(子类转父类),向下(父类转子类),强制转换;方便方法的调用,减少重复的代码。
面向对象14:static关键字详解
static关键字一句话:方便在没有创建对象的情况下进行调用。
被static关键字修饰的不需要创建对象去调用,直接根据类名就可以去访问。
可以看到类加载时,还未调用main方法就已经调用了静态代码块(static随着类加载一起加载)。
main方法中每次创建对象都会先执行匿名代码块再执行构造器,而静态代码块始终只执行了一次。
静态导入包
面向对象15:抽象类
abstract关键字,可修饰抽象方法、抽象类。
抽象类:类的抽象,可没有抽象方法,但有抽象方法的类一定要声明为抽象类。
抽象类不能被实例化,只有抽象类的非抽象子类可以创建对象。
抽象类存在的意义:更利于代码的维护和重用,提高开发效率。
编译器给抽象类添加了一个无参构造方法。
面向对象16:接口的定义与实现
接口最能体现oop的精髓,对 对象 的抽象。
在Java编程语言中是一个抽象类型,是抽象对象的集合,对象通常以interface关键字来声明。
-
普通类:只有具体实现
-
抽象类:具体实现和规范(抽象方法)共存
-
接口:只有规范,无法自己实现
约束和实现分离->面向接口编程
接口就是规范,定义一组规则,它的本质是契约,制定好之后大家都要遵守。
声明
[可见度] interface 接口名称 [extends 其他的接口名] { // 声明变量 // 抽象方法 }
/** * 用户接口,需要实现类 * 锻炼抽象的思维 */ public interface UserService { // 定义的属性默认是静态常量:public static final int age = 10; // 定义的方法是公共抽象:public abstract void add(String str); void delete(String str); void update(String str); void query(String str); }
public interface TimeService { void timer(); }
特性
- 接口是隐式抽象的,当声明一个接口的时候,不必使用abstract关键字。
- 接口中每一个方法也是隐式抽象的,声明时同样不需要abstract关键字。
- 接口中的方法都是公有的。
实现
/** * 抽象类用继承:extends * 接口用实现:implements * 类可以实现接口,需要现实所有方法! * 利用接口实现伪多继承~ */ public class UserServiceImpl implements UserService,TimeService { @Override public void add(String str) { } @Override public void delete(String str) { } @Override public void update(String str) { } @Override public void query(String str) { } @Override public void timer() { } }
类在实现接口的方法时,不能抛出强制性异常,只能在接口中,或者继承接口的抽象类中抛出该强制性异常。
在实现接口的时候,也要注意一些规则:
- 一个类只能继承一个类,但是能实现多个接口。
- 一个接口能继承另一个接口,这和类之间的继承比较相似。
继承
接口的继承使用extends关键字,子接口继承父接口的方法。
// 文件名: Sports.java public interface Sports { public void setHomeTeam(String name); public void setVisitingTeam(String name); } // 文件名: Football.java public interface Football extends Sports { public void homeTeamScored(int points); public void visitingTeamScored(int points); public void endOfQuarter(int quarter); } // 文件名: Hockey.java public interface Hockey extends Sports { public void homeGoalScored(); public void visitingGoalScored(); public void endOfPeriod(int period); public void overtimePeriod(int ot); }
多继承
-
类不允许多继承
-
接口允许多继承。
public interface Hockey extends Sports, Event
接口与类相似,一个接口可以有多个方法。
接口与类的区别:
- 接口不能用户实例化对象。
- 接口没有构造方法。
- 接口中所有的方法必须是抽象方法。
- 接口不能包含成员变量,除了static和final变量。
- 接口不是被类集成,而是被类实现。
- 接口支持多继承。
JDK8之后的新特性,支持在接口中实现具体方法,但需要default修饰。default修饰方法只能在接口中使用。
面向对象17:N种内部类
内部类:在一个类的内部再定义一个类。
Class A{ Class B{ } }
A是B的外部类,B是A的内部类。
成员内部类
public class Outer { private int id ; public void out() { System.out.println("外部类的方法"); } // 成员内部类 public class Inner { public void inner() { System.out.println("内部类的方法"); } // 可以直接使用外部类的属性/方法 public void getOuterId(){ System.out.println("内部类调用外部类属性和方法"); // 创建成员内部类之前肯定要创建外部类对象 // 即使id不是静态变量、out不是静态方法,但创建外部类对象时已经存在。 System.out.println(id); out(); } } }
静态内部类:添加static修饰符
public class Outer { private int id ; public void out() { System.out.println("外部类的方法"); } public static void outStatic() { System.out.println("外部类的静态方法"); } // 静态内部类 public static class Inner { public void inner() { System.out.println("内部类的方法"); } // 可以直接使用外部类的 静态!! 属性/方法 public void getOuterId(){ System.out.println("内部类调用外部类 静态!! 属性和方法"); outStatic(); } } }
局部内部类:局部内部类与局部变量类似,在方法中声明。
public class Outer { public void out() { System.out.println("进入外部类的方法"); // 局部内部类 class Inner { public void inner() { System.out.println("局部内部类与局部变量类似,在方法中声明"); } } Inner inner = new Inner(); inner.inner(); } }
匿名内部类
public class Application { public static void main(String[] args) { // 匿名内部类在多线程中的使用,到时候再深究 Thread thread = new Thread(new Runnable() { @Override public void run() { System.out.println("匿名内部类实现线程的逻辑操作"); } }); // 开启线程 thread.start(); } }
异常处理机制
Java把异常当做对象来处理,并定义了一个基类Java.lang.Throwable作为所有异常的超类。
Java语言定义了许多异常类在Java.lang标准包中,主要分为Error和Exception两大类。
五个关键字try、catch、finally、throw、throws
使用 try 和 catch 关键字可以捕获异常。try/catch 代码块放在异常可能发生的地方。
try/catch代码块中的代码称为保护代码。
finally区可以不要,在IO流,资源关闭时使用。
捕获多个异常:从小到大!
IDEA快捷键:选中监控区域代码 --> Ctrl + Alt + T
抛出异常throws/throw
throws是用在方法名尾部,可以声明抛出多个异常,多个异常之间用逗号隔开。
import java.io.*; public class className { public void withdraw(double amount) throws RemoteException, InsufficientFundsException { // Method implementation } //Remainder of class definition }
throw是用在方法体内,主动抛出异常
public class ThrowTest { public static void main(String[] args) { int a = 1; int b = 0; try { System.out.println(divide(a, b)); } catch (Exception e) { System.out.println("分母不能为0"); //e.printStackTrace(); } } public static double divide(int a, int b) { if (b == 0) { // 主动抛出异常 throw new ArithmeticException(); } return 1.0*a/b; } }
自定义异常类
public class CustomException extends Exception { // 传递数字 private int detail; public CustomException(int detail) { this.detail = detail; } // 打印异常信息 @Override public String toString() { return "CustomException{" + detail + '}'; } }
测试方法test抛出异常throw,再通过throws向外抛出
public class Test { public static void main(String[] args) { try { test(11); } catch (CustomException e) { System.out.println("打印自定义异常信息"); System.out.println(e); } } static void test(int a) throws CustomException { System.out.println("传输一个参数" + a); if (a > 10) { // 抛出自定义异常 throw new CustomException(a); } System.out.println("ok"); } }
总结
-
处理运行是异常时,采用逻辑去合理规避,同时辅助try-catch处理
-
在多重catch块后面,可以加一个catch(Exception)来处理可能会被遗漏的异常
-
对于不确定的代码,也可以加上try-catch,处理潜在的异常
-
尽量去处理异常,切忌只是简单的调用printStackTrace()去打印输出
-
具体如何处理异常,要根据不同的业务需求和异常类型去决定
-
尽量添加finally语句块去释放占用的资源。
垃圾回收GC
为什么需要有垃圾回收机制?
-
在Java中,当一个对象成为垃圾后仍会占用内存空间,时间一长,就会导致内存空间的不足。
-
针对内存空间不足的情况,Java中引入了垃圾回收机制(Java GC Garbage Collection)。
-
有了垃圾回收机制,程序员不需要过多关心垃圾对象回收的问题,Java虚拟机会自动回收垃圾对象所占用的内存空间。
C中汉字占2个字节编码,英文占1个.
Java中汉字占1个字节编码,英文占1个.
-
一个对象在彻底失去引用成为垃圾后会暂时地保留在内存中,当这样的垃圾堆积到一定程度时,Java虚拟机就会启动垃圾回收器将这些垃圾对象从内存中释放,从而使程序获得更多可用的内存空间。
注意:虽然通过程序可以控制一个对象何时不再被任何引用变量所引用,但是却无法精确的控制Java垃圾回收的时机。
回收方式:除了等待Java虚拟机进行自动垃圾回收外,还可以通知系统垃圾回收器进行垃圾回收。
通知系统回收器的方式:
- 调用System类的gc()静态方法:System.gc();
- 调用Runtime对象的gc()实例对象:Runtime.getRuntime.gc().
说明:以上两种方式可以通知启动垃圾回收器进行垃圾回收,但是否立即进行垃圾回收依然具有不确定性。多数情况下,执行后总是有一定的效果。
- 当一个对象在内存中被释放时,它的finalize()方法会被自动调用,finalize()方法是定义在Object类中的实例方法。
- 任何Java类都可以重写Object类的finalize()方法,在该方法中清理该对象占用的资源。如果程序终止之前仍然没有进行垃圾回收,则不会调用失去引用对象的finalize()方法来清理资源
- 只有当程序认为需要更多的额外内存时,垃圾回收器才会自动进行垃圾回收。
Java没有析构函数,Java是一种垃圾收集语言,你无法预测何时一个对象将被销毁.有一个成为继承方法finalize(),但这完全由垃圾收集器决定调用.
在C++中,对象是可以在栈上分配的,也可以在堆上分配。在栈上分配的对象,也就是函数的局部变量,当超出块的"}"时,生命期便结束了。在堆上分配的对象,使用delete的时候,对象的生命期也就结束了。因此在C++中,对象的内存在哪个时刻被回收,是可以确定的(假设程序没有缺陷)。
异或交换两个变量的值
离散数学中同或与异或的区别
同或是判断二者是否相同,相同则为真
异或是判断二者是否相异,相异则为真
a=15 Binary 1111
b=2 Binary 0010
15^2 B 1101 十进制13 x = x ^ y;
x= 1101
y= B 0100
y = x ^ y; 1001 25
int x = 10; int y = 20; x = x ^ y; y = x ^ y; x = x ^ y; System.out.println(x); System.out.println(y);
发表评论 取消回复