Java基础
基础
注释
单行注释// (ctrl +/)
多行注释(ctrl+shift+/)
1
/*文字*/
标识符
- 字母(大小写),数字,下划线,美元符组成,但不能以数字开头
- 大小写敏感
数据类型
基本数据类型,引用数据类型
强类型语言:所有变量先定义后使用
基本数据类型:
数值类型:
- 整数类型:byte(1个字节),short(2个字节),int(默认)(4个字节),long(long数字后要加L)(8个字节)
- 浮点类型:float(float 数字后要加F),double(默认)
- 字符类型:char(2个字节)
boolean:
true false(1位)
引用类型:
- 类
- 接口
- 数组
最好完全避免使用float类型的数字进行比较:float 离散,舍入误差
所有的字符本质上还是数字
1 | |
类型转换
低—–>高
byte,short,char,int,long,float,double
不能对布尔值进行转换
强制转换
- 要避免内存溢出
自动转换
低—>高
注意计算时内存溢出
1
2
3
4
5int money=1000000000;
int yers=20;
int total=money*years//结果为负数
long total2=money*years//也为负,mony years 默认是int 计算之后还是int,在转换之前就出问题了
long total3=money*((long)years)//先把一个数转换成long
数据类型的范围
- byte:-128-127
- short:-32768~32767
- int:-2147483648~2147483647
- long:**-9223372036854775808~9223372036854775807**
变量
类变量(static),实例变量,局部变量
实例变量:(在类里面 main方法外面)
从属于对象,如果不初始化,会有默认值
- 所有的数字默认值是0 或 0.0
- 布尔值默认是:false
- 除基本数据类型外(即引用类型):都是null
类变量:**static** (当然也是在类里面main方法外面)
从属于类,可以直接在main里面直接调用
局部变量:(在main方法里面)
必须声明变量类型和初始值
1 | |
常量
final 常量名 =值
常量名一般使用大写字符
修饰符不存在先后顺序
命名规范
- 所有变量,方法,类名:见名知意
- 类成员变量:首字母小写和驼峰原则(monthSalary)即除第一个单词外后面的单词首字母都大写
- 局部变量: 首字母小写+驼峰原则
- 常量:大写字母和下划线MAX_VALUE
- 类名:首字母大写+驼峰原则 Man GoodMan
- 方法名:首字母小写+驼峰原则
运算符
- long,int,short,byte 进行运算时,有long 的,直接变化为为long ,其余的都是**自动转化为int**
1 | |
关系运算符返回结果:true,false
- instanceof 关系运算符
自增减运算符
1
2
3
4
5
6
7
8int a=3;
int b=a++;
System.out.println(b);//b=3 a=4
int c=++a;
System.out.println(c);//c=5 a=5
System.out.println(a);//a=5逻辑运算符:and or !
位运算符:
&:两个都是1才为1
|:都是0才为0
^:对应位相同为0,不同为1
<<:*2>>:/2连接符+:
1
2
3
4
5
6
7
8
9
10
11
12
13package operator;
public class Dome03 {
public static void main(String[] args) {
int a=10;
int b=20;
System.out.println(a+b);//30
System.out.println(""+a+b);//1020
System.out.println(a+b+"");//30
}
}三元运算符
x ? y : z
包机制
语法格式为:package package1[.package2[.package3...]];
在正式的开发中,一般都采用公司域名倒置来作为包名
导入包,使用import语句将其导入,具体语法如下:import package1[.package2[.package3...]].(ClassName|*);
javaDoc
将注释信息生成帮助文档
1 | |
javaDoc用来生成自己的API文档
生成文档:cmd打开:javadoc -encoding UTF-8 -charset UTF-8 Doc.java UTF-8编码,避免出现非英语字符乱码
在代码文件对应的位置会多出许多文件,index.html打开就是生成的文档
————
Scanner对象
- next接受以空格作为结束标志
- nextLine接受 回车作为结束标志
1 | |
小练习
接受double类型的数字并计算总和及平均值
1 | |
语法
选择结构
if
switch:
注意case穿透现象,写完每个case后都应该加上一个break
jdk7后switch也支持字符串比较即括号里的表达式也可以是字符串(字符串用双引号)
循环结构
while,do…while
for:
(for (int i = 0; i < 100; i++) {}):快捷键:100.for
for(;;) {}死循环
九九乘法表小练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14package com.zhang.struct;
public class Dome02 {
public static void main(String[] args) {
int i=1;int j=1;
for ( i = 1; i < 10; i++) {
for( j=1;j<=i;j++){
System.out.print(j+"*"+i+"="+(i*j)+ "\t");
}
System.out.println();
}
}
}增强for循环:
for(声明语句:表达式){
}
声明语句:声明新的局部变量,该变量的类型必须与数组元素的类型匹配
表达式:要访问的数组名,或者是返回值是数组的方法
之后数组重点使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20package com.zhang.struct;
public class Dome03 {
public static void main(String[] args) {
int[] numbers={10,20,30,40};//定义一个数组
//遍历数组元素 增强for循环
for (int x:numbers) {
System.out.println(x);
}
System.out.println("=======");
//等同于以下for循环
for (int i=0;i<5;i++){
System.out.println(numbers[i]);
}
}
}
小练习打印三角形
1 | |
方法
类似c的函数
1 | |
设计方法的原则:一个方法只完成一个功能,有利于后期去扩展
方法命名规则: 首字母小写+驼峰
方法的定义: 修饰符 返回类型 方法名(参数类型 参数名)
- 修饰符:可选,告诉编译器如何调用该方法,定义了该方法的访问类型
方法的调用:对象名.方法名(实参列表)
方法的重载:
在一个类中有相同的函数名,但形参不同的函数(调用时根据参数类型不同调用)
- 重载规则:
- 方法名称必须相同
- 参数列表必须不同(个数或类型不同或参数排列顺序不同)
- 方法返回类型可以相同也可以不同(重点在于参数那块不同)
- 仅仅返回类型不同不足以成为方法重载
命令行传参
cmd窗口先编译成Dome01.class(命令:javac Dome01.java)
执行编译文件时注意要加上包名,找对路径(在src目录下执行java xxx.xxx.xxx.Dome01 传参)
可变参数
本质是数组
- 在方法声明中,在指定参数类型后加一个省略号…
- 一个方法中只能指定一个可变参数,它必须是方法的最后一个参数
递归
1 | |
数组
声明:
- int[] array1; 首选方法
- int array1[];
开辟空间:array1=new int [10] ;
—–>int[] array2=new int[10];
首先在栈里创建对象,new:在堆里开辟内存空间,在堆里赋值
初始化:
静态初始化:创建以后不可更改
int[] a={1,2,3,4,5};
静态初始化是在声明数组的同时为数组元素赋值。语法如下:
1
2
3
4
5
6// 语法
type[] arrayName = {value1, value2, value3,...};
// 示例
int[] numbers = {1, 2, 3, 4, 5};
String[] fruits = {"apple", "banana", "cherry"};在静态初始化中,数组的大小由花括号内元素的个数自动确定,不需要显式指定。
动态初始化:(包含默认初始化)
int[] b=new int [10];
动态初始化是先声明数组,然后在后续代码中使用
new关键字为数组分配内存空间并指定数组的大小初始化
不同的数据类型在初始化是会有不同的默认值:
数值类型:0
布尔类型:false
引用类型(即除基本类型外的):null
数组默认初始化
1
2
3
4
5
6
7
8
9
10
11// 数值类型数组
int[] intArray = new int[3];
// 数组元素默认值为 0,依次为:0, 0, 0
// 布尔类型数组
boolean[] booleanArray = new boolean[2];
// 数组元素默认值为 false,依次为:false, false
// 引用类型数组
String[] stringArray = new String[4];
// 数组元素默认值为 null,依次为:null, null, null, null
数组特点:
- 数组是相同类型的有序集合,其中的元素可以是任何类型的,包括基本类型和引用类型
- 数组也是对象,数组元素相当于对象的成员变量
- 数组长度是不可变的
增强for循环:
适合打印输出,不适合操作元素
1 | |
数组作为方法的参数和返回值
1 | |
多维数组
1 | |
1 | |
1 | |
Arrays类
Arrays类位于 java.util 包中,主要包含了操作数组的各种方法。
eg:
1 | |
冒泡排序
外层循环:最后一次循环肯定就剩一个数了,所以循环次数为:个数-1次 for(i=0; i<arrar,length-1;i++)
内层循环
每次内层循环是从前(0或1)开始—->往后
接下来比较前后两个数并交换,后面的数if小就是小的数一直往后,if大就是大的数一直往后,最终内循环一次结束后,就可以确定出最后面的是最大值或最小值,下一轮需要比较的数的个数就少一个,内循环几次,下一次比较就可以少比较几个 所以 for(j=0; j<array.length-1-i;j++)
1 | |
稀疏数组
记录有效值及其行列
1 | |
—————
面向对象
本质:
以类的方式组织代码,以对象的组织(封装)数据
三大特性:
封装,继承,多态
从代码的角度:先有类才有对象
回顾方法及加深
1 | |
return&& break:
return :标志方法的结束,返回一个结果或者空
break:跳出switch循环,结束循环
方法调用:
静态方法
1 | |
非静态方法
1 | |
加static的方法与类一起加载,非静态的方法,实例化后才存在
在同一个类中,可以直接在main方法中调用其他静态方法,
调用其他非静态的方法:
1 .在main中先new 实例化,再调用
2 .或者 非静态方法改成静态方法(加static)
值传递&&引用传递:
值传递传递形参,另外开辟了一块内存
引用传递,将类实例化得到实例化对象,实例化对象传递时直接指向同一块内存传递
类与对象的创建
- 一个程序应该只有一个main方法
使用new关键字创建对象:
使用new关键字创建对象时,除了分配内存空间,还会给创建好的对象进行默认的初始化以及类中的构造器的调用
1 | |
类是对象的模板,对象是类的实例,就像以上Student类中属性name,age不能写死,它只是一个模板,对象就是它的实例,用对象来调用属性进行赋值,[创建对象时默认初始化属性(daming 的name=null age=0)]
所以回到了开始那句话:面向对象编程的本质是:以类的方式组织代码,以对象的组织(封装)数据
构造器详解
类中的构造器也叫构造方法,是在创建对象时必须调用的,并且构造器具有以下两个特点:
1 .必须和类的名称相同2 .必须没有返回类型,也不能写void
一个类即使什么也没有写,它也有一个默认构造器
显示定义构造器(它其实就是一个特殊的无返回值的方法):
1
2
3
4
5
6
7
8package com.oop.dome02;
public class Person {
public Person() {
}
}构造器的作用:
实例化初始值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23package com.oop.dome02;
public class Person {
String name;
public Person() {
this.name="lili";
}
}
package com.oop.dome02;
public class Application {
public static void main(String[] args) {
//new 实例化对象
Person person = new Person();
System.out.println(person.name);//lili
}
}所以实例化对象的属性:
- 可以通过在main中实例化对象后用对象.属性赋值(即使用默认无参构造器),
- 可以在类中通过 显示无参构造器(属性写死)
- 有参构造器初始化(属性传参 new时传参)
有参构造&&无参构造
1 | |
new 实例化,本质在调用构造器,会自动根据参数判断,有参数的直接调用有参构造器 (方法重载)。构造器用来初始化值,在构造器中
this.属性直接就可以赋值注意:一旦定义了有参构造,并且也无参实例化了(无参创建对象),无参构造就必须显式定义,否则会报错
默认类中是有无参构造的,写了有参构造,无参构造就没有了,就需要显式定义
alt+insert 快捷键默认生成有参构造器
定义不同有参构造器即方法重载,在类中创建不同的属性,不同属性作为构造器参数实现方法重载
创建对象内存分析

小总结
类是一个模板(抽象的),对象是一个具体的实例
方法:定义,调用
对象是通过引用来操作的:栈—–>堆(地址)
属性:字段 Field 成员变量
初始化 :数字0 0.0
char : u0000
boolean: false
引用: null
修饰符 属性类型 属性名=属性值
- 对象的创建和使用:
- 必须使用new关键字创造对象 ,构造器
- 对象的属性方法调用:
对象名.属性 对象.方法
- 类:静态的属性,动态的方法
封装
程序追求 高内聚低耦合
高内聚就是:类的内部数据操作细节自己完成,不允许外部干涉;低耦合:仅暴露少量的方法给外部使用
属性私有 get/set (alt + insert 快捷键生成get/set方法)
关键字private 就不能直接 s1.name 来操作 借助get方法返回name 调用的方法得到name
1 | |
思考:不借助set方法的话,有参构造器也可以直接初始化属性
所以又体现出来构造器就是特殊的方法
1 | |
使用属性的时候再传参即可,构造器在new的时候就会调用,在new的时候直接传参
封装的好处:
规避不合法的数据,在set方法中设置条件
1 | |
好处:
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统可维护增加
继承
继承的本质是对一批类的抽象
关键字 extends 子类是父类的扩展
继承是类与类之间的一种关系,类与类之间的关系还有依赖,组合,聚合等
继承关系的两个类,一个为子类(派生类),一个为父类(基类)。
只要子类继承了父类,实例化子类对象,对象也可以用父类中的属性和方法
1 | |
修饰符:public(要加public,才能用子类创建的对象调用父类的属性)protected,default,private(私有的 子类不能继承私有属性,要借助get,set)
在java中所有的类都默认直接或间接继承object类,也可以显示定义继承object类
java中只有单继承(即一个儿子对应一个爸爸)
犯的错误:
在父类中定义方法无返回值,使用子类创建的对象调用该方法时,因为该方法无返回值,不能直接输出,可以直接调用就好
super详解
子类的方法中访问父类的属性或方法
super.属性或方法回顾:
this.属性或方法调用当前类中的属性或方法在方法中可以互相直接调用方法
以下代码实现了 通过子类方法执行类的其他方法,和子类方法中调用父类方法
Person 父类:
1 | |
Student 子类:
1 | |
main:
1 | |
this && super
1 | |
有参构造&& 无参构造
以下部分代码 输出: Person无参构造
Student无参构造
new的时候就根据实际类型调用构造器,若是子类构造器,在子类构造器中有隐藏的调用父类构造器的代码 super()
Person s1 = new Person(); //只调用Person 构造器1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
*x显示调用父类的构造器必须在子类的构造器第一行*
``` java
public class Dome01 {
public static void main(String[] args) {
Student s1 = new Student(); //输出 Person无参构造 Student无参构造
// s1.text2();
}
}
//*******以下为父类**********
package com.oop.dome04;
public class Person {
public Person() {
System.out.println("Person无参构造");
}
}
//*********以下为子类*************
package com.oop.dome04;
public class Student extends Person {
public Student() {
//在子类的构造方法中隐藏代码super() new的时候调用父类的无参构造
// super();//调用父类的构造器必须在子类的构造器第一行
System.out.println("Student无参构造");
}
}当子类定义一个有参构造后,无参构造就会消失,就不会默认new的时候调用父类的无参构造了——>只要定义了一个有参构造,就必须显示定义无参构造
小总结:
super 注意点:
- super 调用父类的构造方法,必须在构造方法的第一个
- super必须只能出现在子类的方法或者构造方法中去调用父类的方法或属性
- super() 和this() 不能同时调用构造方法,因为他们都要写在第一行
super VS this:
代表对象不同:this :代表调用者这个对象 super:代表父类对象的应用前提: this :没有继承也可以使用 super : 只能在继承条件下才能使用
构造方法:this() 本类的构造 super() 父类的构造
方法重写
重写都是方法重写,与属性无关
方法重写只与非静态方法有关,与静态方法无关
定义的什么类(等号左边的)就调用的什么类的静态方法,回想之前学的方法的调用,静态方法可以直接用类调用(它随类一起加载)
1 | |
然而 非静态方法 与以上的静态方法不同
1 | |
理解:
静态方法属于类,非静态方法属于对象
静态时方法随类一起加载,new 的b 是B类(等号左边),因此执行B类方法
非静态时,子类重写了父类的方法,都执行子类方法
小总结
重写存在于子类父类,有了继承才能在子类中重写父类的方法
子类父类的方法名必须相同,(alt+insert快捷键重写方法自动给就可以实现)
参数列表也必须相同(不同那就是
方法的重载啦,也不是,方法的重载是在一个类中的)子类重写的方法的修饰符范围只能比父类的修饰符扩大,
public>protected>default(默认什么都不写的)>private
抛出异常:范围,可以缩小,不能扩大
ClassNotFoundException(小异常)—->Exception(大异常)
为什么需要重写:
父类的功能子类不需要,或者不一定满足!
快捷键:alt+insert 选择重写方法
多态
1 | |
一个对象的实际类型是确定的,但引用类型是不确定的
方法重写后,父类的引用类型调用子类的方法(相比继承:子类继承父类的方法和属性),(多态讲的父类何时能调用子类的方法)
当方法只有子类中有的时候,父类调用不了子类的,需要强制类型转换(继承时子类自然继承父类的)
对象能执行哪些方法看左边引用类型:
子类的引用类型能调用继承的父类的方法
而父类的引用类型不能调用子类独有的(要强制类型转换),能调用子类重写后的
注意事项:
多态时方法的重写,属性没有多态
创建对象时父类和子类有联系,要注意类型转换异常! ClassCastException!
多态存在条件:继承关系,方法重写,父类引用指向子类对象
不能重写的方法
static 方法,不属于实例,属于类,
final 修饰的是常量
private 方法
instanceof
instanceof是Java中的一种关键字,用于判断一个对象是否属于某个类或其子类
在Java中,instanceof关键字通过比较
对象的类型和类的类型来判断对象的实例关系。其底层实现原理是通过比较对象的类型和类的类型在内存中的地址。如果两者相同或者具有继承关系,则返回true;否则返回false。
1 | |
小总结:
X instanceof Y
X:对象 Y:类或接口
*编译*:看对象左边的引用类型(如以下例子为:Object),比较引用类型和Y之间是否存在父子类关系,存在则成功编译。(以上面代码@@@标记处为编译失败的例子)
*执行*:看对象右边的实际类型(如以下例子为:Student),比较实际类型和Y之间是否存在父子类关系,存在就输出true 。(以上代码###标记处为输出false的例子)
eg:
Object s1=new Student();==父类引用指向子类对象==
System.out.println(s1 instanceof Student);
还有一点注意:
执行比较时:不是比较实际类型嘛,但***必须 实际类型 是Y的子类或就是Y类才输出ture,***实际类型如果是Y的父类则输出false
(输出false的情况: 实际类型是Y的父类或他们两个不存在父子类关系)
1
2
3
4
5
6
7//引用类型Object 实际类型Person
Object object = new Person();
System.out.println(object instanceof Student);//false Person是Student的父类输出为false
System.out.println(object instanceof Object);//ture
System.out.println(object instanceof Person);//ture
System.out.println(object instanceof Teacher);//false 同理 Person 是Teacher的父类输出false
System.out.println(object instanceof String);// false 这里就是不存在父子关系输出false
类型转换
对象引用类型为父类,不能通过对象调用子类中独有的方法
如果引用类型为父类,通过对象调用父类子类共有的方法(就是多态啦)
1 | |
强制类型转换 存在条件:父类引用指向子类对象
直接 父类引用指向父类对象 创建不能强制类型转换()
会报ClassCastException的错误
父类转换为子类,向下转型,强制转换
static
非静态方法必须new一个对象后才能用对象调用,
静态方法跟类一起就加载出来了,可以直接 类.方法 调用
在同一个类中也可以直接写方法调用,非静态方法中也是可以调用静态方法的
new的时候自动调用静态代码块(只执行一次),匿名代码块,构造方法
1 | |
发现了一个比较好玩的:
new的时候调用顺序为静态代码块,匿名代码块,构造方法
调用构造方法的时候是根据对象的实际类型调用的!
- new Student (),实际类型是子类就调用子类构造器并且先执行之前学习的隐藏代码super()即先调用父类的构造器,再调用子类的构造器
- new Person(),实际类型是父类就直接调用父类构造器了
1 | |
遗留一个问题:静态代码,匿名代码写在了Person 类中
new一个 引用属性,实际属性都是Student的对象 也会调用静态代码,匿名代码
静态导入包:
1 | |
- final 修饰常量,如果类被final修饰是没有办法作为父类继承的
static 静态方法
父类是静态方法,子类是不能重写的
抽象类
- 抽象类本质也是类,是由abstract声明的类 (abstract class) extends :单继承 (接口可以实现多继承)
- 子类继承抽象类后,必须实现抽象方法,除非该子类也必须声明为抽象类。
1 | |
特点:
- 抽象类不能new,无法实例化,只能靠子类去实现它
- 抽象类里面也可以有普通方法,但一旦有了抽象方法就必须是在抽象类里面
接口
普通类:只有具体实现方法
抽象类:具体实现方法和定义(抽象方法)都有!
接口:只有抽象方法的定义! 约束和实现分离
接口的本质是契约,声明接口的关键词是:interface
接口中定义的所有属性,只能是常量,默认修饰符public static final
接口中定义的所有方法,默认什么都不写的修饰符public abstract
没有构造方法
实现类:一般以impl结尾 一个类实现一个接口通过 implements 关键字,并且一个实现类必须重写接口里面的所有方法
实现类实现多个接口,要重写里面的所有抽象方法,如果接口中的方法重名,只需要在实现类中重写一次即可,重写的方法既代表对接口1中方法的重写,又代表对接口2中的方法的重写
1 | |
- 接口里面定义的都是抽象方法,定义常量 静态常量方法
作用:
- 约束
- 在接口中定义一些方法(没有方法体),让不同的 实现类 实现,实现接口必须重写方法
- 接口不能实例化,没有构造方法。接口中没有方法实现(和抽象类一样),
- implements 可以实现多个接口
抽象类和接口的共同点
都是为了让方法抽象,再让子类去实现
都不能实例化本类对象,只能让子类实例化对象
接口与类之间的关系:
类于类的关系:继承,只能是单继承,不能多继承,(单继承多继承主体是下一级 单继承 多继承)但可以是多层继承
类与接口之间的关系:实现关系,实现类 来 实现接口
接口与接口之间的关系:继承关系(也是extends关键字),可以单继承,*也可以多继承*
若实现类实现的是最下面的子接口的话,需要重写这个体系中所有的抽象方法
N种内部类
- java 一个类 中可以有多个class 但只能有一个public class
1 | |
总结:
实例化内部类对象时,先实例化一个外部的对象,再通过这个外部对象new内部对象
//实例化外部类 Outer outer = new Outer(); //通过外部类对象new内部类来实例化内部类~ Outer.Inner inner = outer.new Inner();1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
- ***子类对象访问父类私有属性和方法,内部类对象访问外部类私有属性和方法***,通过在子类或内部类写类似get方法即可获取到
***
**静态内部类**
以上代码的内部类加上static 就是静态内部类了
- 静态内部类可以直接访问外部类的静态成员,但不能访问外部类的实例成员
- 静态内部类中 获取外部类的私有属性和方法的代码就会出错:因为先实例化的外部对象,static 静态内部类先加载出来,而外部类的实例成员还没有加载出来
**匿名内部类:**
``` java
package com.oop.dome10;
public class Test {
public static void main(String[] args) {
/*Apple apple = new Apple();
apple.eat();*/
//没有名字初始化类,不用将实例保存单变量中~
new Apple().eat();
//new 接口实例化对象
//下面这个类其实就是一个实现类,匿名内部类
UserService userService = new UserService() {
//不重写接口方法的话会报错
@Override
public void hello() {
System.out.println("hello");
}
};//注意这里的分号
}
}
//下面的在Test类外面写
class Apple{
public void eat(){
System.out.println("1");
}
}
//接口
interface UserService{
void hello();
}
异常
Exception
异常指程序运行中出现的不期而至的各种状况:文件找不到,网络连接失败,非法参数,异常发生在程序运行期间,它影响了程序正常执行流程
int a=10 int b=0; int res=a/b;//1.异常是程序当执行到a/b 时,因为 b=0,程序就会出现(抛出)异常,ArithmeticException(算术异常) //2.当抛出异常后,程序就退出,崩溃了 //3.这样一个不算致命的错误导致程序崩溃 不好 //4.所以需要异常处理机制来解决这个问题 System.out.println("程序继续运行");1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
- 异常分为两大类:
Error:(错误) JVM无法解决的严重错误 eg: 栈溢出 Error 是严重错误,程序会崩溃
Excpetion: 分为两大类: 运行时异常(程序运行时异常)和编译时异常(编程时编译器就检查出异常)
- java把异常当作对象来处理,并定义一个基类java.lang.Throwable 作为所有异常的超类
***
#### **异常处理机制**
- 进行了异常处理,即使出现了异常,程序仍可继续执行
*try-catch-finally*
- 将一段可能有问题的代码选中 ctrl+alt+t 使用try-catch-finally 捕获
```java
try{
//可能异常的代码
}catch(Exception e){
//当捕获到异常时,系统将异常封装成Exception 对象e 传递给catch
}finally{
//不管try代码块是否有异常,最终都要执行finally
//所以一般将关闭资源放在finally中
}
throws(投掷)
try-catch-finally 和throws 二选一,程序员如果没有显示处理异常,默认throws
将发生的异常抛出,交给调用者(方法来处理),最顶级的处理者就是JVM
throw 后面的异常类型可以是方法中产生的异常类型,也可以是它的父类
1 | |

1 | |
捕获多个异常:
1 | |
Java异常详解(全文干货) - 个人文章 - SegmentFault 思否
自定义异常
当程序中出现了某些“错误”,但该错误信息并没有在Throwable子类中描述处理,这个时候可以自己设计异常类,用于描述该错误信息
步骤:
- 定义类:自定义异常类名,继承Exception 或RuntimeException
- 如果继承Exception ,属于编译异常
- 如果继承RuntimeException ,属于运行异常(一般都是继承RuntimeExceptipn)
即我们把自定义异常作为运行时异常(好处可以使用默认的处理机制)
1 | |

throw vs throws:
throws :代表异常处理方式 位于方法声明中 后面跟异常类型
1
throws AgeExceptionthrow: 是手动生创建异常对象的关键字 位于方法体中 后面跟异常对象
1
throw new SelfException("年龄需要在18~120之间");