类初始化过程
由一个面试题开始,此段代码输出的结果
public class Father {
private int i = test();
private static int j = method();
/**
* 静态代码块
*/
static {
System.out.println("(1)");
}
/**
* 父类构造方法
*/
Father() {
System.out.println("(2)");
}
/**
* 普通代码块
*/ {
System.out.println("(3)");
}
/**
* 普通方法
*
* @return
*/
public int test() {
System.out.println("(4)");
return 1;
}
/**
* 静态方法
*
* @return
*/
public static int method() {
System.out.println("(5)");
return 1;
}
}
public class Son extends Father {
private int i = test();
private static int j = method();
/**
* 静态代码块
*/
static {
System.out.println("(6)");
}
/**
* 构造代码块
*/
Son() {
System.out.println("(7)");
}
/**
* 普通代码块
*/ {
System.out.println("(8)");
}
/**
* 普通方法
*
* @return
*/
public int test() {
System.out.println("(9)");
return 1;
}
/**
* 静态方法
*
* @return
*/
public static int method() {
System.out.println("(10)");
return 1;
}
public static void main(String[] args) {
}
}
输出结果:(5)(1)(10)(6)
类初始化过程
- 一个类药创建实例需要先加载并初始化该类
main方法所在的类需要先加载和初始化 - 一个子类要初始化需要先初始化父类
- 一个类初始化就是执行"<clinit>()"方法
<clinit>()方法由静态变量显示赋值代码和静态代码块组成
类变量显示赋值代码和静态代码块代码从上到下顺序执行
<clinit>()方法只执行一次
通过字节码查看
Compiled from "Father.java"
public class com.study.interview.classload.Father {
private int i;
private static int j;
com.study.interview.classload.Father();
Code:
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: aload_0
6: invokevirtual #2 // Method test:()I
9: putfield #3 // Field i:I
12: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #5 // String (3)
17: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #7 // String (2)
25: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
public int test();
Code:
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #8 // String (4)
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: ireturn
public static int method();
Code:
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #9 // String (5)
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: ireturn
static {};
Code:
0: invokestatic #10 // Method method:()I
3: putstatic #11 // Field j:I
6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #12 // String (1)
11: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: return
}
Compiled from "Son.java"
public class com.study.interview.classload.Son extends com.study.interview.classload.Father {
private int i;
private static int j;
com.study.interview.classload.Son();
Code:
0: aload_0
1: invokespecial #1 // Method com/study/interview/classload/Father."<init>":()V
4: aload_0
5: aload_0
6: invokevirtual #2 // Method test:()I
9: putfield #3 // Field i:I
12: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
15: ldc #5 // String (8)
17: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
23: ldc #7 // String (7)
25: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
28: return
public int test();
Code:
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #8 // String (9)
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: ireturn
public static int method();
Code:
0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #9 // String (10)
5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: iconst_1
9: ireturn
public static void main(java.lang.String[]);
Code:
0: return
static {};
Code:
0: invokestatic #10 // Method method:()I
3: putstatic #11 // Field j:I
6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #12 // String (6)
11: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
14: return
}
子类初始化的时候,先初始化父类
另一个面试题结束,此段代码输出的结果
/**
* Father类不变
*/
public class Son extends Father {
private int i = test();
private static int j = method();
/**
* 静态代码块
*/
static {
System.out.println("(6)");
}
/**
* 构造代码块
*/
Son() {
System.out.println("(7)");
}
/**
* 普通代码块
*/ {
System.out.println("(8)");
}
/**
* 普通方法
*
* @return
*/
public int test() {
System.out.println("(9)");
return 1;
}
/**
* 静态方法
*
* @return
*/
public static int method() {
System.out.println("(10)");
return 1;
}
public static void main(String[] args) {
//新增代码
Son son1 = new Son();
System.out.println();
Son son2 = new Son();
}
}
输出结果:
(5) (1) (10) (6) (9) (3) (2) (9) (8) (7)
(9) (3) (2) (9) (8) (7)
实例初始化过程
- 实例初始化及时执行<init>()方法
<init>()方法可能重载有多个,有几个构造器就有几个<init>()方法
<init>()方法由非静态实例变量显示赋值代码和非静态代码块、对应构造代码组成
非静态实例变量显示赋值代码和非静态代码块代码从上到下顺序执行,而对应构造器的代码最后 执 行
每次创建实例对象,调用对象构造器,执行的就是对应<init>方法
<init>方法的首行是super()或super(实参列表),即对应的<init>方法 - 方法的重写
不能被重写的方法有: final方法、静态方法、private等子类中不可见方法
能够重写的方法:public修饰的方法、默认方法 - 对象的多态
子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
非静态方法默认的调用对象是this
this对象在构造器或者<init>方法中就是正在创建的对象 如:在创建Son方法的时候,需要先构造父类方法,此时this代表的是Son的实例