一、final关键字的几点注意点(9/17)
1、final修饰数据。
(1)final修饰基本类型变量,代表该变量是常量不能被再次初始化。(final修饰成员变量一定要进行初始化,否则编译报错,修饰一般变量时,在使用之前需要进行初始化。)
【final修饰的变量-常量,在类加载的准备阶段,进行赋初始值,而且是赋常量的值。】
Static修饰变量表示该变量属于类变量,可以修改内容。类加载准备阶段,赋的是零值。
https://blog.youkuaiyun.com/zxd8080666/article/details/78087646
(2)final修饰引用类型变量,代表该引用不能指向其他引用变量。
final变量有点类似C中的宏替换,但是这种替换只有在编译期能够确定final修饰的变量的值,编译器才能对变量直接进行替换。
例1:
public static void main(String[] args) {
String a = "hello2";
final String b = "hello";
String d = "hello";
String c = b + 2;
String e = d + 2;
System.out.println((a == c));
System.out.println((a == e));
}
结果: true,false
因为第一个b是final修饰的,编译期可以确定的值。
例2:
public static void main(String[] args) {
String a = "hello2";
final String b = getHello();
String c = b + 2;
System.out.println((a == c));
}
public static String getHello() {
return "hello";
}
结果: false,false
因为b在编译期无法确定值。
2、final修饰方法。
final修饰的方法,代表该方法在子类中不可以被重写。子类中有相同的函数签名也不是对父类方法的重写。(同函数名的方法重载不受影响。)
3、final修饰类。
final修饰的类,不可以被继承。final不可以修饰abstract类,匿名内部类中所有变量必须是final变量。
ps:
(1)final关键字容易与finalize()方法搞混,后者是在Object类中定义的方法,是在垃圾回收之前被JVM调用的方法。
(2)接口中声明的所有变量本身是final的。
(3)final和abstract这两个关键字是反相关的,final类就不可能是abstract的。
(4)final方法在编译阶段绑定,称为静态绑定(static binding)。
参考:https://www.jb51.net/article/157603.htm
二、finally的注意点(9/17)
首先,不管有没有异常抛出或者try-catch中有无return。finally中语句都会执行!
这是为了使得finally中的一些对资源的释放、关闭不受影响。
(1)finally中有return,编译器会有警告(finally block does not complete normally,finally语句块没有正常完成)那么try-catch中无论return还是抛异常,finally中的return都会覆盖返回值。只返回finally中的return的值。
(2)finally中没有return,try-catch中有return,那么return和抛异常是正常输出的。如果finally中对return的变量进行修改,那么不会影响到返回值的大小。
try-catch-finally的执行顺序:
(1)try中执行到return(如果有return)之前所有语句,包括return中的运算语句。(相当于返回值已经确定了)。
(2)catch捕获try中运行语句的异常。程序执行catch块中return之前(包括return语句中的表达式运算)代码。
(3)执行finally中语句(没有return不能改变1、2的返回结果),如果有return覆盖1、2返回结果。
例1:
// finally修改变量值
public static int fun() {
int a = 2;
try {
return a + 1;
} catch (Exception e) {
} finally {
a = -1;
// return -1;
}
return 0;
}
public static void main(String[] args) {
System.out.println(fun());
}
程序运行结果:返回值为3.
例2:
// finally中return变量值
public static int fun() {
int a = 2;
try {
return a + 1;
} catch (Exception e) {
} finally {
return -1;
}
}
public static void main(String[] args) {
System.out.println(fun());
}
程序运行结果:-1.
参考:https://blog.youkuaiyun.com/u011277123/article/details/59074492
三、static关键字的初始化顺序(9/17)
静态变量和静态代码块初始化,先于实例变量和普通语句块。静态变量、静态代码块之间初始化顺序取决于自身的代码顺序。
最后才是构造函数的初始化。
重点:存在继承的初始化顺序。
(1)父类的静态变量、静态代码块。
(2)父类的实例变量、普通语句块初始化。
(3)父类的构造函数初始化。
####################################
(4)子类的静态变量、静态代码块执行。
(5)子类的实例变量、普通语句块初始化。
(6)子类的构造函数初始化。