一道题看懂Java调用顺序和初始化(大概
这段代码的输出结果是什么?
public class Test {
Person person = new Person("Test");
static{
System.out.println("test static");
}
public Test() {
System.out.println("test constructor");
}
public static void main(String[] args) {
new MyClass();
}
}
class Person{
static{
System.out.println("person static");
}
public Person(String str) {
System.out.println("person "+str);
}
}
class MyClass extends Test {
Person person = new Person("MyClass");
static{
System.out.println("myclass static");
}
public MyClass() {
System.out.println("myclass constructor");
}
}
输出结果为:
test static
myclass static
person static
person Test
test constructor
person MyClass
myclass constructor
为什么输出结果是这样的?我们来分析下这段代码的执行过程:
找到main方法入口,main方法是程序入口,但在执行main方法之前,要先加载Test类
加载Test类的时候,发现Test类有static块,而是先执行static块,输出test static结果
然后执行new MyClass(),执行此代码之前,先加载MyClass类,发现MyClass类继承Test类,而是要先加载Test类,Test类之前已加载
加载MyClass类,发现MyClass类有static块,而是先执行static块,输出myclass static结果
然后调用MyClass类的构造器生成对象,在生成对象前,需要先初始化父类Test的成员变量,执行Person person = new Person("Test")代码,发现Person类没有加载
加载Person类,发现Person类有static块,而是先执行static块,输出person static结果
接着执行Person构造器,输出person Test结果
然后调用父类Test构造器,输出test constructor结果,这样就完成了父类Test的初始化了
再初始化MyClass类成员变量,执行Person构造器,输出person MyClass结果
最后调用MyClass类构造器,输出myclass constructor结果,这样就完成了MyClass类的初始化了
以上来源于:https://blog.csdn.net/kuangay/article/details/81485324
如果不认识不会用static更要看一看,或者看我的精简版https://www.cnblogs.com/UC0087/p/18831255
构造代码块/代码初始块/游离代码块:没有任何前后缀,只有一对{}括起来的代码。
加载顺序为:父类静态代码块>子类静态代码块>父类游离代码块>父类构造器>子类游离代码块>子类构造器
其中的游离代码块实际上是在构造器中执行的,并且会放在构造器的前端,按顺序执行,这就造成了游离代码块>构造器这样的顺序
但是我还是不明白 ”然后调用MyClass类的构造器生成对象,在生成对象前,需要先初始化父类Test的成员变量,执行Person person = new Person("Test")代码“ 这段,主要有两大疑问
person是成员变量?
是的,person既是引用变量,也属于成员变量,下面为你详细解释这两个概念以及person为何符合这两种身份。
引用变量
在 Java 里,引用变量存储的是对象在内存中的地址,而非对象本身。通过引用变量,可以对其所指向的对象进行访问和操作。在代码 Person person = new Person(); 中,person 就是一个引用变量,它指向通过 new Person() 创建的 Person 对象。
成员变量
成员变量是定义在类中、方法之外的变量,它属于类的一部分,用于描述类的属性或状态,person 定义在 Test 类中、方法之外,所以它是 Test 类的成员变量
调用构造方法需要对成员变量进行初始化?
是的,在 Java 里,调用构造方法之前会先对成员变量进行初始化。下面详细解释这个过程以及背后的原理。
具体的初始化流程
当创建一个类的对象时,JVM 会按照以下顺序完成对象的初始化工作:
- 内存分配:JVM 为对象在堆内存中分配一块足够的空间。
- 默认初始化:将对象的所有成员变量设置为默认值。例如,数值类型(如
int、double等)会被初始化为 0 或者 0.0,布尔类型会被初始化为false,引用类型会被初始化为null。 - 显式初始化:按照成员变量在类中声明的顺序,依次执行显式的初始化代码。这包含直接在声明成员变量时赋予的初始值,以及初始化块中的代码。
- 构造方法执行:最后调用类的构造方法,完成对象的其他初始化操作。
显然,person作为成员变量被显式初始化了。
注意事项:static静态代码块随类只加载一次
什么时候会初始化父类的成员变量?


new实例化之解解析
在Person person = new Person();语句中,各部分的称呼及含义如下:
1. Person(等号左边)
- 称呼:类名,也代表数据类型。
- 含义:在 Java 中,类是创建对象的模板,它定义了对象的属性和行为。当你使用
Person作为数据类型声明变量时,意味着该变量将引用Person类的一个对象。
2. person
- 称呼:对象引用变量,简称引用变量。
- 含义:引用变量用于存储对象在内存中的地址,通过这个变量可以访问和操作它所指向的对象。在这个语句里,
person变量存储着通过new Person()创建的Person对象的内存地址,后续可以通过person来调用Person类中的属性和方法。
3. =
- 称呼:赋值运算符。
- 含义:用于将等号右边表达式的结果赋值给等号左边的变量。在这里,就是把
new Person()创建的对象的内存地址赋给person引用变量。
4. new
- 称呼:关键字。
- 含义:在 Java 里,
new关键字的作用是在堆内存中为对象分配存储空间,并调用相应类的构造方法来初始化对象。当执行new Person()时,系统会在堆内存中开辟一块空间用于存储Person对象,并调用Person类的构造方法对对象进行初始化。
5. Person()
- 称呼:构造方法调用。
- 含义:构造方法是类中的一种特殊方法,其名称与类名相同,主要用于在创建对象时进行初始化操作。这里的
Person()是Person类的无参构造方法,当执行new Person()时,会自动调用该构造方法来完成对象的初始化工作。如果Person类中没有显式定义构造方法,Java 编译器会提供一个默认的无参构造方法。

浙公网安备 33010602011771号