【Java高频面试题】--类的初始化过程以及实例的初始化过程
程序员文章站
2022-07-14 15:14:55
...
1.1 类的初始化过程
- 要创建一个类的实例,必须加载和初始化该类。
- main()方法所在的类,会被优先加载并初始化
- 子类初始化前,会先加载并初始化它的父类
- 初始化一个类,其实质上就是执行了
<client>()
方法-
<client>()
方法包含了,静态变量显式赋值代码以及静态代码块 - 静态变量显式赋值代码以及静态代码块的执行顺序,由它们的先后顺序执行,先声明的先执行
-
-
<client>()
方法只会执行一次
如以下代码:
//静态变量显式赋值代码
private static int j=method();
//静态代码块
static {
System.out.println("(1)");
}
public static int method(){
System.out.println("(5)");
return 1;
}
相应字节码:
// access flags 0x9
public static method()I
L0
LINENUMBER 40 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(5)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 41 L1
ICONST_1
IRETURN
MAXSTACK = 2
MAXLOCALS = 0
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 14 L0
INVOKESTATIC com/qingyun/demo/load/Father.method ()I
PUTSTATIC com/qingyun/demo/load/Father.j : I
L1
LINENUMBER 18 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(1)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L2
LINENUMBER 19 L2
RETURN
MAXSTACK = 2
MAXLOCALS = 0
1.2 实例的初始化过程
- 实例化一个类其实质上是执行了
<init>()
方法。- 类中有多少个构造器就会有多少个
<init>()
方法。
- 类中有多少个构造器就会有多少个
-
<init>()
方法由非静态显式赋值代码、非静态代码块组成以及对应的构造器代码组成。 -
<init>()
方法的执行顺序是,优先执行非静态显式赋值代码、非静态代码块,它们俩那个在前那个先执行,构造器对应代码最后执行。 - 每次创建实例,调用构造器,就是调用其对应的
<init>()
方法。 - 需要注意的是,在子类中,
<init>()
方法的第一行是super()方法,即对应的父类的<init>()
方法
如下代码:
父类代码:
package com.qingyun.demo.load;
/**
* Created with IntelliJ IDEA.
* User: 李敷斌.
* Date: 2020-05-11
* Time: 13:49
* Explain: 父类
*/
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)");
}
public int test(){
System.out.println("(4)");
return 1;
}
public static int method(){
System.out.println("(5)");
return 1;
}
}
父类对应字节码:
// class version 52.0 (52)
// access flags 0x21
public class com/qingyun/demo/load/Father {
// compiled from: Father.java
// access flags 0x2
private I i
// access flags 0xA
private static I j
// access flags 0x0
<init>()V
L0
LINENUMBER 22 L0
ALOAD 0
INVOKESPECIAL java/lang/Object.<init> ()V
L1
LINENUMBER 12 L1
ALOAD 0
ALOAD 0
INVOKEVIRTUAL com/qingyun/demo/load/Father.test ()I
PUTFIELD com/qingyun/demo/load/Father.i : I
L2
LINENUMBER 28 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(3)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L3
LINENUMBER 23 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(2)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L4
LINENUMBER 24 L4
RETURN
L5
LOCALVARIABLE this Lcom/qingyun/demo/load/Father; L0 L5 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x1
public test()I
L0
LINENUMBER 34 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(4)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 36 L1
ICONST_1
IRETURN
L2
LOCALVARIABLE this Lcom/qingyun/demo/load/Father; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x9
public static method()I
L0
LINENUMBER 40 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(5)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 41 L1
ICONST_1
IRETURN
MAXSTACK = 2
MAXLOCALS = 0
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 14 L0
INVOKESTATIC com/qingyun/demo/load/Father.method ()I
PUTSTATIC com/qingyun/demo/load/Father.j : I
L1
LINENUMBER 18 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(1)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L2
LINENUMBER 19 L2
RETURN
MAXSTACK = 2
MAXLOCALS = 0
}
子类代码:
package com.qingyun.demo.load;
/**
* Created with IntelliJ IDEA.
* User: 李敷斌.
* Date: 2020-05-11
* Time: 13:49
* Explain: 子类
*/
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)");
}
@Override
public int test(){
System.out.println("(9)");
return 1;
}
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();
}
}
子类对应字节码:
// class version 52.0 (52)
// access flags 0x21
public class com/qingyun/demo/load/Son extends com/qingyun/demo/load/Father {
// compiled from: Son.java
// access flags 0x2
private I i
// access flags 0xA
private static I j
// access flags 0x0
<init>()V
L0
LINENUMBER 22 L0
ALOAD 0
INVOKESPECIAL com/qingyun/demo/load/Father.<init> ()V
L1
LINENUMBER 12 L1
ALOAD 0
ALOAD 0
INVOKEVIRTUAL com/qingyun/demo/load/Son.test ()I
PUTFIELD com/qingyun/demo/load/Son.i : I
L2
LINENUMBER 28 L2
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(8)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L3
LINENUMBER 23 L3
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(7)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L4
LINENUMBER 24 L4
RETURN
L5
LOCALVARIABLE this Lcom/qingyun/demo/load/Son; L0 L5 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x1
public test()I
L0
LINENUMBER 35 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(9)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 37 L1
ICONST_1
IRETURN
L2
LOCALVARIABLE this Lcom/qingyun/demo/load/Son; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
// access flags 0x9
public static method()I
L0
LINENUMBER 41 L0
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(10)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L1
LINENUMBER 42 L1
ICONST_1
IRETURN
MAXSTACK = 2
MAXLOCALS = 0
// access flags 0x9
public static main([Ljava/lang/String;)V
L0
LINENUMBER 46 L0
NEW com/qingyun/demo/load/Son
DUP
INVOKESPECIAL com/qingyun/demo/load/Son.<init> ()V
ASTORE 1
L1
LINENUMBER 48 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
INVOKEVIRTUAL java/io/PrintStream.println ()V
L2
LINENUMBER 50 L2
NEW com/qingyun/demo/load/Son
DUP
INVOKESPECIAL com/qingyun/demo/load/Son.<init> ()V
ASTORE 2
L3
LINENUMBER 51 L3
RETURN
L4
LOCALVARIABLE args [Ljava/lang/String; L0 L4 0
LOCALVARIABLE son1 Lcom/qingyun/demo/load/Son; L1 L4 1
LOCALVARIABLE son2 Lcom/qingyun/demo/load/Son; L3 L4 2
MAXSTACK = 2
MAXLOCALS = 3
// access flags 0x8
static <clinit>()V
L0
LINENUMBER 14 L0
INVOKESTATIC com/qingyun/demo/load/Son.method ()I
PUTSTATIC com/qingyun/demo/load/Son.j : I
L1
LINENUMBER 18 L1
GETSTATIC java/lang/System.out : Ljava/io/PrintStream;
LDC "(6)"
INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V
L2
LINENUMBER 19 L2
RETURN
MAXSTACK = 2
MAXLOCALS = 0
}
这里需要注意的是,以上代码中涉及到了方法的重写:
- 重写指的是子类重写父类的方法,其方法名与父类对应方法相同
- 访问修饰符的访问权限不能够更低
- 被final、static、private关键字修饰的方法不能够被重写。
所以当实例化子类成员是,调用的是子类中重写的test()方法。
对象的多态性:
- 子类如果重写了父类的方法,通过子类对象调用的一定是子类重写过的代码
- 非静态方法默认的调用对象是this
- this对象在构造器或者说
<init>
方法中就是正在创建的对象
实例的初始化顺序流程图(省略类的加载以及初始化过程):
推荐阅读
-
荐 浅谈Java中类和对象的初始化、实例化以及方法重载的底层机制
-
java对象初始化的过程和原理
-
【Java高频面试题】--类的初始化过程以及实例的初始化过程
-
java类被实例化之后各类属性的初始化顺序(实例化某个类,那么这个类也会被jvm加载)
-
静态变量、实例变量初始化时机,以及子类隐藏父类成员时,创建子类对象的一些问题
-
总结一个某东的面试题 --- java类的初始化时机
-
荐 浅谈Java中类和对象的初始化、实例化以及方法重载的底层机制
-
java对象初始化的过程和原理
-
java类被实例化之后各类属性的初始化顺序(实例化某个类,那么这个类也会被jvm加载)
-
Java对象的创建:类的初始化时机与过程