前言
零基础学习java已经有一段时间了,不知不觉java基础的学习已经接近尾声,为巩固所学知识,故作此文章。(学习资源来源于尚硅谷)
一 数据类型
1 基本数据类型
1.1整型
整形包含byte short int long,他们分别占据一字节,二字节,四字节,十六字节。 整型的意思便是整数。 在java中,我们可以通过 数据类型 变量名; 方法来声明变量,如下
?
byte a;
short b;
int c;
long d;
?
我们也可以一次性声明多个变量,如下
?
int a,b,c,d;
?
赋值操作如下
?
int a;
long b;
a = 1;
b = 2l;
?
按规定来说,long类型的变量需要在赋值的数字后面添加l。
1.2浮点型
浮点型包含了float与double,分别占据四字节与八字节。 基本使用方法与整型相同,不过需要注意在为float赋值的时候,赋值数值后面添加f。
1.3布尔型
boolean,布尔型的使用比较特殊,他只能存放true 以及 false 两种值。
1.4 字符型
char,字符型的使用比较奇怪,我放下如下代码
char a;
a = 'a';
System.out.println(a);
a = 5;
System.out.println(a);
在这种情况下,输出结果分别为a与一未知符号。 并且我发现,在没有为char赋值添加’'的时候,char型变量是不能被赋值除了一位数字以外的其他字符的。 报错为cannot be resolved to a variable。 但是当我进行如下尝试时
char a;
a = 'a';
System.out.println(a + 1);
a = 9;
System.out.println(a + 1);
输出结果为98和10。 在这里,拥有’‘的变量参与运算的是他的ascll码,而没有’'的变量则是本身。
2 引用数据类型
2.1 接口 2.2 数组 2.3 类 这里只需要有个印象,这里提到的东西在下文都会描述。
二 运算符
1 算术运算符
1.1 +
这个符号有三个意思,分别表示正好,加法,连接 我用下列代码来表示
int a = 1;
String b = "啊";
int c = +1;
System.out.println(a + c);
System.out.println(a + b);
这里的输出结果为2 以及 1啊 是不是能很明显感受出三种用法
1.2 –
这个符号表示减法以及负号。
1.3 *
这个符号表示乘法。
1.4 /
这个符号表示除法,注意他不会除得小数。 例如 3 / 2 = 1
1.5 %
这个符号表示取余 例如 5 % 1 = 0
1.6 前++
表示运算前自加一,代码如下
int a = 1;
System.out.println(++a);
这里输出结果为2
1.7 后++
表示运算后自加一,代码如下
int a = 1;
System.out.println(a++);
System.out.println(a);
输出结果为1 2 这样是不是能理解前后++的区别了
1.8前–
运算前自减一
1.9后–
运算后自减一
2 赋值运算符
在看完上面的之后,这里应该没有问题了,就不赘余了
2.1 +=
2.2 -=
2.3 *=
2.4 /=
2.5 %=
2.6 =
3 比较运算符
3.1 >
3.2 <
3.3 ==
在基本数据类型中是判断相等,在引用数据类型中判断地址值是否相等。
3.4 >=
3.5 <=
3.6 !=
不等于
3.7 instaceof
判断是否为该类型,这个在后面的多态中会更好运用,暂时不讲。
4 逻辑运算符
或且非的意思相信高中基本也知道了,便不赘余。
4.1 |
或
4.2 ||
短路或,短路的意义在于,在你已经能判定此逻辑的正确与否时,是否继续执行。 举例说明。 小明有一个苹果,现在我执行语句 小明拥有的苹果数 > 0 || ++小明的苹果数 > 5; 很容易知道,在||前列的表达式已经能判断出语句整体为true,但是在语句后面,我让小明的苹果数增加了一个,如果这是|,则小明的苹果数会变成2,但是这里是||,语句已经能判断出为true了,不需要再执行后面的语句,所以小明的苹果数为1.
4.3 &
且
4.4 &&
短路且
4.5 !
非
4.6 ^
不相同
5 位运算符
这个东西很离谱,是争对数据底层二进制码的,了解一下吧
5.1 <<
按二进制形式把所有的数字向左移动对应的位数,符号不变,高位移除(舍弃),低位补零。
5.2 >>
按二进制形式把所有的数向右移动对应的位数,低位移出(舍弃),正数的高位的空位补0,负数的高位的空位补1
5.3 >>>
按二进制形式把所有的数字向右移动相对应的位数,低位移出(舍弃),高位的空位补零(无论正数负数都补零)
5.4 ~
只对一个操作数进行运算,将操作数二进制中的1改为0,0改为1.
5.5 &
参与运算的数字,低位对齐,高位不足的补零,如果对应的二进制位同时为1,那么计算结果才为1,否则为0。因此,任何数与0按位与运算,其结果都为0。
5.6 |
参与运算的数字,低位对齐,高位不足的补零。只要对应的二进制位有一个为1,那么结果就为1,否则为0
5.7 ^
参与运算的数字,低位对齐,高位不足补零,如果对应的二进制位相同,结果为0,否则结果为1。 因为在计算机中使用补码表示,最高位为1表示负数。补码求原码的方法是最高位符号不变,其余各位求反,再加1。
6 三元运算符
这个用的比较少,能用的也能if else,我就只说一下格式了 (条件表达式)? 表达式1 : 表达式2 若条件表达式为true,执行1 反之,执行2
三 流程控制
1 分支结构
1.1 if else
结构如下
if(a > 1) {
}
else if(a < 1) {
}
else {
}
1.2 switch case
int a = 1;
switch(a) {
case 1:
case 2:
case 3:
default:
}
分享一下我遇到的坑吧,switch case,如果没有写break,只要进去一个,就会把后面的全部执行。 我们一般只在数量较少时使用switch case,但是能用switch case的时候一般要使用switch case,因为他的执行效率更高。
2 循环结构
2.1 for
格式如下
for(int i = 1;i < 10;i++) {
}
for(初始化条件;循环条件;递送条件)
2.2 while
int a = 1;
while(a < 10) {
System.out.println("a");
a++;
}
注意递送条件一般要写,不然会一直循环。
2.3 do while
int a = 1;
do {
}while(a < 10);
这个需要注意,他是先执行再判断,所以无论如何他都会执行一次。
四 数组
1 一维数组
你需要明白,数组的意思是在堆,开辟出一段连续的空间,放置有顺序的数据。 数组在声明时,必须确认长度,且一段确认长度,则长度不会改变。 数组相关的概念:数组名,元素,角标、下标、索引,数组的长度(元素的个数)。 注意数组的排序是从0开始的。
1.1 声明
格式:动态初始化 数据类型[] 变量名 = new 数据类型[数组长度]; 动态初始化 数据类型[] 变量名 = new 数据类型[]{数组元素}; 代码如下
int[] a = new int[3];
int[] b = new int[] {1,2,3};
1.2 调用
通过 变量名[索引数] 来调用。
a[1] = 1;
1.3 初始化
在我们将数组的数据类型定义时,数组便默认给数据一个初始化值 验证如下
int[] a = new int[3];
float[] b = new float[3];
char[] c = new char[3];
boolean[] d = new boolean[3];
System.out.println(a[1]);
System.out.println(b[1]);
System.out.println(c[1]);
System.out.println(d[1]);
输出结果为 0 0.0 ‘0’ false 注意,char的’0’表示为空格
1.4 遍历
遍历说的通俗一点就是讲数组的元素全部输出 要注意的就是数组的索引是从0开始的。
int[] a = new int[3];
for(int i = 0;i < a.length;i++) {
System.out.println(a[i]);
}
1.5 内存解析
在前文中说过,数组是引用数据类型。 对于引用数据类型的变量,我们给的是地址值,就像一个遥控器指向堆空间的具体数组。
2 二维数组
二维数组相较于一维数组更有意思
2.1 声明
int[][] a = new int[3][];
int[][] b = new int[5][3];
二维数组好像是没有动态初始化这种说话的
2.2 调用
如果你知道面向对象思维,你会发现一些比较有意思的现象,数组和面向对象思想有一些相似之处。
a[2] = new int[3];
b[2] = new int[6];
以及注意,我定义的数组变量a,他是不能调用内层的,因为还没有定义,那么就是一层是null,内存不能调用,调用则报错。
2.3 初始化
若初始化方式为int[][] num1 = new int[2][1];
则外层元素的初始化值为:十六进制地址值
则内层元素的初始化值为:与一维数组的初始化情况相同
若初始化方式为int[][] num1 = new int[2][];
则外层元素的初始化值为:null
则内层元素的初始化值为:不可调用,需要声明
2.4 遍历
for(int i = 0;i < num1.length;i++) {
for(int a = 0;a < num1[i].length;a++) {
System.out.print(num1[i][a]);
}
System.out.println();
}
2.5 内存解析
遥控器操控遥控器来操控数据。 我觉得head frist java里面对这部分解释的很好。
五 面向对象
1类与对象
1.1类的创建
①类的基本结构
类具有 属性 构造器 代码块 方法 声明如下
public class classtest {
String name;
int age;
public classtest(){
System.out.println("这是构造器");
}
{
System.out.println("这是代码块");
}
public void method(){
System.out.println("这是一个方法");
}
}
Ⅰ属性
声明方法为 数据类型 变量名; 属性可以被权限修饰符,static,final,权限修饰符修饰。
Ⅱ构造器
声明方法为 类名; 构造器可以被权限修饰符修饰,不能被static ,final修饰
Ⅲ代码块
声明方法为 {} 代码块可以被static修饰,不能被final修饰。
Ⅳ方法
声明方法为 权限修饰符 返回值类型 方法名(){} 方法可以被权限修饰符,static,final修饰
②类的使用
非静态类的使用必须通过创建对象才能调用类的一切结构。
1.2对象的建立
模板: 数据类型 对象名 = new 数据类型;
2 封装性
简单来说便是将类里面的属性,修饰为private,使其不能在其他类中被直接调用,以至于我们必须设置对应的get以及set方法。 如下
private int a;
public void setA(int a) {
this.a = a;
}
public int getA() {
return a;
}
3 继承性
通过子类继承父类,使子类具有父类的一切属性及方法。 可以减少代码的冗余。 模板 class son extends father{ }
4 多态性
在项目实践中用的比较多。 可以这样声明 father son = new son();
5 静态
static可以用来修饰:属性、方法、代码块、内部类
使用static修饰属性:静态变量(或类变量)
属性,按是否使用static修饰,又分为:静态属性 vs 非静态属性(实例变量) 实例变量:我们创建了类的多个对象,每个对象都独立的拥有一套类中的非静态属性。当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值的修改。 静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量。当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。 static修饰属性的其他说明: ① 静态变量随着类的加载而加载。可以通过"类.静态变量"的方式进行调用 ② 静态变量的加载要早于对象的创建。 ③ 由于类只会加载一次,则静态变量在内存中也只会存在一份:存在方法区的静态域中。 ④调用 静态变量 实例变量 类 可以 不可以 对象 可以 可以 3.3 静态属性举例:System.out; Math.PI;
使用static修饰方法:静态方法
① 随着类的加载而加载,可以通过"类.静态方法"的方式进行调用 ②调用 静态方法 非静态方法 类 能 不能 对象 能 能 ③ 静态方法中,只能调用静态的方法或属性 非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性
static注意点:
5.1 在静态的方法内,不能使用this关键字、super关键字 5.2 关于静态属性和静态方法的使用,大家都从生命周期的角度去理解。
开发中,如何确定一个属性是否要声明为static的?
属性是可以被多个对象所共享的,不会随着对象的不同而不同的。 类中的常量也常常声明为static
6 final
final可以用来修饰的结构:类、方法、变量
final 用来修饰一个类:此类不能被其他类所继承。
比如:String类、System类、StringBuffer类
final 用来修饰方法:表明此方法不可以被重写
比如:Object类中getClass();
final 用来修饰变量:此时的"变量"就称为是一个常量
final修饰属性:可以考虑赋值的位置有:显式初始化、代码块中初始化、构造器中初始化
final修饰局部变量:
尤其是使用final修饰形参时,表明此形参是一个常量。当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。 static final 用来修饰属性:全局常量
7 abstract
abstract可以用来修饰的结构:类、方法
abstract修饰类:抽象类
此类不能实例化 抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程) 开发中,都会提供抽象类的子类,让子类对象实例化,完成相关的操作
abstract修饰方法:抽象方法
抽象方法只有方法的声明,没有方法体 包含抽象方法的类,一定是一个抽象类。反之,抽象类中可以没有抽象方法的。 若子类重写了父类中的所有的抽象方法后,此子类方可实例化 若子类没有重写父类中的所有的抽象方法,则此子类也是一个抽象类,需要使用abstract修饰
abstract使用上的注意点:
①abstract不能用来修饰:属性、构造器等结构 ②abstract不能用来修饰私有方法、静态方法、final的方法、final的类
8 super与this
this.表明是本类的某结构。 super.表明是父类的某结构。 在构造器中,如果没有自定义this或者super,会自动生成空参super,调用父类,所以我们写父类一般要给一个空参构造器。 super与this需要定义在首行。
9 权限修饰符
private defalut(缺省) protected public 按照权限大小,能做到被 同一个类 同一个包 不同包的子类 同一个项目 所调用
10 重写与重载
重载
重载(Overloading) 重载发生在本类,方法名相同,参数列表不同,与返回值无关,只和方法名,参数列表,参数的类型有关. 重载(Overload):首先是位于一个类之中或者其子类中,具有相同的方法名,但是方法的参数不同,返回值类型可以相同也可以不同。 (1):方法名必须相同 (2):方法的参数列表一定不一样。 (3):访问修饰符和返回值类型可以相同也可以不同。 其实简单而言:重载就是对于不同的情况写不同的方法。 比如,同一个类中,写不同的构造函数用于初始化不同的参数。
重写
重写发生在父类子类之间,比如所有类都是继承与Object类的,Object类中本身就有equals,hashcode,toString方法等.在任意子类中定义了重名和同样的参数列表就构成方法重写. 重写(override):一般都是表示子类和父类之间的关系,其主要的特征是:方法名相同,参数相同,但是具体的实现不同。 重写的特征: (1):父类被重写的方法的返回值类型是void,则子类重写的方法的返回值类型只能是void 父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值类型可以是A类或A类的子类 (2):参数列表必须相同 (3):访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类的一个方法被声明为public,那么在子类中重写该方法就不能声明为protected。 (4):子类和父类在同一个包中,那么子类可以重写父类所有方法,除了声明为private和final的方法。 (5):构造方法不能被重写, (6)子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型(具体放到异常处理时候讲) 子类和父类中的同名同参数的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写) (7) 父类被重写的方法的返回值类型是基本数据类型(比如:double),则子类重写的方法的返回值类型必须是相同的基本数据类型(必须也是double)
11 ==与equals
简单来说
基本数据类型
== 与 equals都是比较数值
引用数据类型
== 比较的是地址值 equals在没重写之前也是比较地址值,所以大部分情况下我们需要对equals进行重写
面试题模式
一、回顾 == 的使用:
== :运算符
-
可以使用在基本数据类型变量和引用数据类型变量中 -
如果比较的是基本数据类型变量:比较两个变量保存的数据是否相等。(不一定类型要相同)如果比较的是引用数据类型变量:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体 补充: == 符号使用时,必须保证符号左右两边的变量类型一致。 输出的结果是true或者false。 二、equals()方法的使用: -
是一个方法,而非运算符 -
只能适用于引用数据类型 -
Object类中equals()的定义: public boolean equals(Object obj) { return (this == obj); } 说明:Object类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同.即两个引用是否指向同一个对象实体 -
像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象的"实体内容"是否相同。 -
通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的"实体内容"是否相同。那么,我们就需要对Object类中的equals()进行重写. 重写的原则:比较两个对象的实体内容是否相同.
12 包装类
java提供了8种基本数据类型对应的包装类,使得基本数据类型的变量具有类的特征
掌握的:基本数据类型、包装类、String三者之间的相互转换
①String类型 —>基本数据类型、包装类:调用包装类的parseXxx(String s)代码如下
String a = “aaaaa”;
Int num = Integer.parseInt(a);
Integer num1 = Integer.parseInt(a);
注意这里是会报错。只能传递数字。
②基本数据类型、包装类—>String类型:调用String重载的valueOf(Xxx xxx)
int a = 1;
String b = a + "";
方式2:调用String的valueOf(Xxx xxx)
String c = String.valueof(a);
③基本数据类型 —>包装类:调用包装类的构造器
int a = 1;
Integer b = new Integer(a);
④包装类—>基本数据类型:调用包装类Xxx的xxxValue()
Integer b = new Integer(1);
int a = b.intValue();
JDK 5.0 新特性:自动装箱 与自动拆箱
自动装箱
Int num1 = 1;
Integer num2 = num1;
自动拆箱
Integer num1 = new Integer(1);
Int num2 = num1;
13 接口
接口的使用 1.接口使用interface来定义 2.Java中,接口和类是并列的两个结构 3.如何定义接口:定义接口中的成员 3.1 JDK7及以前:只能定义全局常量和抽象方法 全局常量:public static final的.但是书写时,可以省略不写 抽象方法:public abstract的 3.2 JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法(略) 4. 接口中不能定义构造器的!意味着接口不可以实例化 5. Java开发中,接口通过让类去实现(implements)的方式来使用. 如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化 如果实现类没有覆盖接口中所有的抽象方法,则此实现类仍为一个抽象类 6. Java类可以实现多个接口 —>弥补了Java单继承性的局限性 格式:class AA extends BB implements CC,DD,EE 7. 接口与接口之间可以继承,而且可以多继承 8. 接口的具体使用,体现多态性
14 内部类(参考「懒妹子学IT」的文章)
因为我对内部类没有掌握很好,所以部分来自于该博主。
一、什么是内部类?把一个类放在另一个类的内部部,这就是内部类。广义上我们将内部类分为四种:成员内部类、静态内部类、局部(方法)内部类、匿名内部类。
二、为什么要用内部类?
使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。——《Think in java》 也就是说内部类拥有类的基本特征。(eg:可以继承父类,实现接口。)在实际问题中我们会遇到一些接口无法解决或难以解决的问题,此时我们可以使用内部类继承某个具体的或抽象的类,间接解决类无法多继承引起的一系列问题。(注:内部类可以嵌套内部类,但是这极大的破坏了代码的结构,这里不推荐使用。) 除了上面的优点之外还有如下四点: 1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。 2、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。 3、内部类提供了更好的封装,除了该外围类,其他类都不能访问。 4、创建内部类对象的时刻并不依赖于外围类对象的创建。 具体来说,内部类信息(属性、方法)可以和外部类重名;内部类是具有类的基本特征的独立实体;可以利用访问修饰符隐藏内部类的实施细节,提供了更好的封装;静态内部类使用时可直接使用,不需先创造外部类。 4、静态内部类小结【和成员内部类对比理解(区别异同)】 内部可以包含任意的信息。 静态内部类的方法只能访问外部类的static关联的信息。 利用 外部类.内部类 引用=new 外部类.内部类(); 然后利用引用.成员信息(属性、方法)调用。 访问内部类的静态信息,直接外部类.内部类.静态信息就可以了。 静态内部类可以独立存在,不依赖于其他外围类。 3、方法内部类小结【局部内有很多局限,应注意作用域】 类前不能有访问修饰符。 仅在此方法内使用。 无法创造静态信息。 可以直接访问方法内的局部变量和参数(有限制,下面详谈),但是不能更改。 可以随意的访问外部类的任何信息 4、匿名内部类小结【匿名内部类常常被用来重写某个或某些方法】 匿名内部类是没有访问修饰符的。 使用匿名内部类时,这个new之后的类首先是要存在的,其次我们要重写new后的类的某个或某些方法。 匿名内部类访问方法参数时也有和局部内部类同样的限制。 匿名内部类没有构造方法
15 方法形参
方法的形参的传递机制:值传递
1.形参:方法定义时,声明的小括号内的参数 实参:方法调用时,实际传递给形参的数据 2.值传递机制: 如果参数是基本数据类型,此时实参赋给形参的是实参真实存储的数据值。 如果参数是引用数据类型,此时实参赋给形参的是实参存储数据的地址值。
可变个数形参
1.jdk 5.0新增的内容 2.具体使用: 2.1 可变个数形参的格式:数据类型 … 变量名 2.2 当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。 2.3 可变个数形参的方法与本类中方法名相同,形参不同的方法之间构成重载 2.4 可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载。换句话说,二者不能共存。(因为本质算相同的) 2.5 可变个数形参在方法的形参中,必须声明在末尾 2.6 可变个数形参在方法的形参中,最多只能声明一个可变形参。 其实相当于数组形参,且可以进行遍历。
16 package与import
一、package关键字的使用
1.为了更好的实现项目中类的管理,提供包的概念 2.使用package声明类或接口所属的包,声明在源文件的首行 3.包,属于标识符,遵循标识符的命名规则、规范(xxxyyyzzz)、“见名知意” 4.每"."一次,就代表一层文件目录。 补充:同一个包下,不能命名同名的接口、类。 不同的包下,可以命名同名的接口、类。
二、import关键字的使用
import:导入
- 在源文件中显式的使用import结构导入指定包下的类、接口
- 声明在包的声明和类的声明之间
- 如果需要导入多个结构,则并列写出即可
- 可以使用"xxx."的方式,表示可以导入xxx包下的所有结构
- 如果使用的类或接口是java.lang包下定义的,则可以省略import结构
- 如果使用的类或接口是本包下定义的,则可以省略import结构
- 如果在源文件中,使用了不同包下的同名的类,则必须至少有一个类需要以全类名的方式显示。
- 使用"xxx."方式表明可以调用xxx包下的所有结构。但是如果使用的是xxx子包下的结构,则仍需要显式导入
- import static:导入指定类或接口中的静态结构:属性或方法。
17 匿名(没搞懂)
匿名内部类
匿名内部类也就是没有名字的内部类正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写,但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口,但最多只能继承一个父类,或实现一个接口。
关于匿名内部类还有如下两条规则: 1)匿名内部类不能是抽象类,因为系统在创建匿名内部类的时候,会立即创建内部类的对象。因此不允许将匿名内部类定义成抽象类。 2)匿名内部类不等定义构造器(构造方法),因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义实例初始化块 一般来说,new 一个对象时小括号后应该是分号,也就是new出对象该语句就结束了。但是出现匿名内部类就不一样,小括号后跟的是大括号,大括号中是该new 出对象的具体的实现方法。因为我们知道,一个抽象类是不能直接new 的,必须先有实现类了我们才能new出它的实现类。上面的伪代码就是表示new 的是Father的实现类,这个实现类是个匿名内部类。
匿名对象
new 数据类型();
18 toString
部分数据类型重写了该方法,一般我们调用需要重写,否则出现hashcode值。
19 返回值
return 作用: ① 结束方法 ② 针对于有返回值类型的方法,使用"return 数据"方法返回所要的数据。 ③注意点:return关键字后面不可以声明执行语句。 ④方法的使用中,可以调用当前类的属性或方法
20 instanceof
instanceof A:判断对象a是否是类A的实例。如果是,返回true;如果不是,返回false 使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型。 如果类B是类A的父类。若 a instanceof A返回true,则 a instanceof B也返回true.
21 创建对象时的执行顺序
①默认初始化
②显式初始化/⑤在代码块中赋值(看先后写)
③构造器中初始化
④有了对象以后,可以通过"对象.属性"或"对象.方法"的方式,进行赋值
执行的先后顺序:① - ② / ⑤ - ③ - ④
异常处理
一、异常的处理:抓抛模型
过程一:“抛”:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象。 并将此对象抛出。 一旦抛出对象以后,其后的代码就不再执行。 关于异常对象的产生:① 系统自动生成的异常对象 ② 手动的生成一个异常对象,并抛出(throw) 过程二:“抓”:可以理解为异常的处理方式:① try-catch-finally ② throws
二、try-catch-finally的使用
try{ //可能出现异常的代码 }catch(异常类型1 变量名1){ //处理异常的方式1 }catch(异常类型2 变量名2){ //处理异常的方式2 }catch(异常类型3 变量名3){ //处理异常的方式3 } … finally{ //一定会执行的代码 } 说明:
- finally是可选的。
- 使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象
的类型,去catch中进行匹配 - 一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理。一旦处理完成,就跳出当前的
try-catch结构(在没有写finally的情况)。继续执行其后的代码 - catch中的异常类型如果没有子父类关系,则谁声明在上,谁声明在下无所谓。
catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面。否则,报错 - 常用的异常对象处理的方式: ① String getMessage() ② printStackTrace()
- 在try结构中声明的变量,再出了try结构以后,就不能再被调用
- try-catch-finally结构可以嵌套
体会1:使用try-catch-finally处理编译时异常,是得程序在编译时就不再报错,但是运行时仍可能报错。 相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。 体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了。 针对于编译时异常,我们说一定要考虑异常的处理。
try-catch-finally中finally的使用:
1.finally是可选的 2.finally中声明的是一定会被执行的代码。即使catch中又出现异常了,try中有return语句,catch中有 return语句等情况。 3.像数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的 释放。此时的资源释放,就需要声明在finally中的。
异常处理的方式二:throws + 异常类型
- "throws + 异常类型"写在方法的声明处。指明此方法执行时,可能会抛出的异常类型。
一旦当方法体执行时,出现异常,仍会在异常代码处生成一个异常类的对象,此对象满足throws后异常 类型时,就会被抛出。异常代码后续的代码,就不再执行! - 体会:try-catch-finally:真正的将异常给处理掉了。
throws的方式只是将异常抛给了方法的调用者。 并没有真正将异常处理掉。 - 开发中如何选择使用try-catch-finally 还是使用throws?
3.1 如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果 子类重写的方法中有异常,必须使用try-catch-finally方式处理。 3.2 执行的方法a中,先后又调用了另外的几个方法,这几个方法是递进关系执行的。我们建议这几个方法使用throws 的方式进行处理。而执行的方法a可以考虑使用try-catch-finally方式进行处理。
如何自定义异常类?
- 继承于现有的异常结构:RuntimeException 、Exception
- 提供全局常量:serialVersionUID
- 提供重载的构造器
总结
对于内部类,匿名内部类使用很迷茫。 日后再补充其中内容。
|