(一)前言
本文讨论的是静态代码块,实例代码块,父类构造方法,子类构造方法的执行顺序,以及final关键字的作用
(二)初始化顺序
(1)演示结果
下列代码中,我定义了静态代码块,实例代码块,父类构造方法,子类构造方法。
public class Father {
static {
System.out.println("父类静态代码块");
}
{
System.out.println("父类实例代码块");
}
public Father() {
System.out.println("父类构造方法");
}
}
class Children extends Father {
static {
System.out.println("子类静态代码块");
}
{
System.out.println("子类实例代码块");
}
public Children() {
System.out.println("子类构造方法");
}
public static void main(String[] args) {
Children chirldren1 = new Children();
System.out.println("===============");
Children children2 = new Children();
}
}
运行观察执行顺序,结果如下图
(2)小结
1.
父类静态代码块优先于子类静态代码块执行,且是最早执行
2.
父类实例代码块和父类构造方法紧接着执行
3.
子类的实例代码块和子类构造方法紧接着再执行
4.
第二次实例化子类对象时,父类和子类的静态代码块都将不会再执行
(三)final关键字
final关键字的修饰范围:
final关键字可以修饰修饰类、方法、变量以及方法的形参。
(1)final修饰类
当final修饰一个类时,表示
该类不能被继承,即该类为最终类,不能有子类
如下图,final修饰Father类后,表示不能被继承,当子类children继承Father类后,编译器报错
(2)final修饰方法
当final修饰一个方法时,表示该方法
不能被子类重写,即该方法为最终方法,子类不能对其进行修改。子类可以继承这个方法,但不能定义一个新的方法来覆盖它。
如下图final修饰fatherMethod方法后,表示该方法不能被重写,子类重写会报错
(3)final修饰变量
3.1final修饰成员变量
当final修饰一个成员变量时,表示该变量为常量,即该变量的值一旦被初始化之后就不能被修改
如下图中成员变量a被fianl修饰后,表示常量,当对a重新赋值时会报错
3.2final修饰局部变量
1.final修饰
普通的基本数据类型的局部变量和修饰成员变量类似。
2.当fianl修饰
引用类型的变量时表示final修饰的变量所持有的引用不能改变,而非引用所指向的对象本身不能改变。
解析:final修饰的变量所持有的引用不能改变
如下代码中我们使用引用类型StringBuilder来举例,我们用final关键字修饰了新创建的sb变量,那么final所修饰的相当于是下图栈中所显示的0xff3不能改变,这个0xff3的意义相当于是堆中存放hello字符串的地址,0xff3不能改变,相当于sb这个变量
不能再指向新的对象
(如图中不能再指向0xff4)。
public static void main(String[] args){
final StringBuilder sb = new StringBuilder("Hello");
// sb = new StringBuilder("World"); // 这行代码会编译错误,因为sb是final修饰的,不能重新赋值
sb.append(" World"); // 这是允许的,因为我们没有改变sb的引用,只是修改了它引用的对象
System.out.println(sb.toString()); // 输出 "Hello World"
}
解析:而非引用所指向的对象本身不能改变
如下图,final修饰后只是0xff3这个存储对象地址的值不能改变,但是
对象本身却能够改变
,如上面代码中通过append()函数再hello后追加world字符串。
(4)小结
1.final修饰类表示此类不能被继承
2.final修饰方法表示方法不能被重写
3.final修饰基本类型变量表示此变量为常量不能被修改,
final修饰引用类型变量表示final修饰的变量所持有的引用不能改变,而非引用所指向的对象本身不能改变。