java 类加载及实例化的调用顺序
1.没有继承的情况
单独一个类的场景下,初始化顺序为依次为 静态变量和静态代码块(看两者的书写顺序),继承的基类的构造函数,成员变量,被调用的构造函数。
代码呈现:
public class Test {
public static void main(String[] args) {
Son son = new Son();
}
}
class Son {
public Son() {
System.out.println("this is son.");
}
public Son(int age) {
System.out.println("son is " + age + " years old.");
}
private Height height = new Height(1.8f);
static {
System.out.println("this is static code");
}
public static Gender gender = new Gender(true);
}
class Height {
public Height(float height) {
System.out.println("initializing height " + height + " meters.");
}
}
class Gender {
public Gender(boolean isMale) {
if (isMale) {
System.out.println("this is a male.");
} else {
System.out.println("this is a female.");
}
}
}
this is static code
this is a male.
initializing height 1.8 meters.
this is son.
2.继承的情况
稍微修改一下代码,添加两个基类,让Son继承Father, Father继承Grandpa。
继承的情况就比较复杂了。由于继承了基类,还将往上回溯,递归地调用基类的无参构造方法。
在我们的例子中,在初始化静态数据后,会先往上追溯,调用Father的默认构造方法,此时再往上追溯到Grandpa的默认构造方法。
注:如果在子类的构造方法中,显式地调用了父类的带参构造方法,那么JVM将调用指定的构造方法而非默认构造方法。
基类和子类均有静态数据,成员变量和构造方法的场景
我们继续修改代码,让其最终呈现如下:
public class Test {
public static void main(String[] args) {
Son son = new Son();
}
}
class Grandpa {
public Grandpa() {
System.out.println("this is grandpa.");
}
public Grandpa(int age) {
System.out.println("grandpa is " + age + " years old.");
}
private Height height = new Height(1.5f);
public static Gender gender = new Gender(true, "grandpa");
static {
System.out.println("this is static code");
}
}
class Father extends Grandpa {
public Father() {
System.out.println("this is father.");
}
public Father(int age) {
System.out.println("father is " + age + " years old.");
}
private Height height = new Height(1.6f);
public static Gender gender = new Gender(true, "father");
}
class Son extends Father {
public Son() {
super(50);
System.out.println("this is son.");
}
public Son(int age) {
System.out.println("son is " + age + " years old.");
}
private Height height = new Height(1.8f);
public static Gender gender = new Gender(true, "son");
}
class Height {
public Height(float height) {
System.out.println("initializing height " + height + " meters.");
}
}
class Gender {
public Gender(boolean isMale) {
if (isMale) {
System.out.println("this is a male.");
} else {
System.out.println("this is a female.");
}
}
public Gender(boolean isMale, String identify) {
if (isMale) {
System.out.println(identify + " is a male.");
} else {
System.out.println(identify + " is a female.");
}
}
}
grandpa is a male.
this is static code
father is a male.
son is a male.
initializing height 1.5 meters.
this is grandpa.
initializing height 1.6 meters.
father is 50 years old.
initializing height 1.8 meters.
this is son.
在我们的示例中,加载顺序应该是这样的:
Grandpa 静态数据
Father 静态数据
Son 静态数据
Grandpa 成员变量
Grandpa 构造方法
Father 成员变量
Father 构造方法
Son 成员变量
Son 构造方法
一般来说,顺序如下:
1.首先是父类的静态变量和静态代码块(看两者的书写顺序);
2.第二执行子类的静态变量和静态代码块(看两者的书写顺序);
3.第三执行父类的成员变量赋值
4.第四执行父类类的构造代码块
5.第五执行父类的构造方法
6.执行子类的构造代码块
7.第七执行子类的构造方法
总结,也就是说虽然客户端代码是new 的构造方法,但是构造方法确实是在整个实例创建中的最后一个调用。
先静态:具体是先父静态>子静态。
先父后子:先父的全部,然后后子的全部。
优先级:父类>子类,静态代码块>非静态代码块>构造函数(与位置前后无关系)
java 类加载及实例化的调用顺序的更多相关文章
- Java类加载及实例化的调用顺序
标题起得略拗口,大概意思就是说在一个Java类中,域和构造方法的调用顺序. 1. 没有继承的情况 单独一个类的场景下,初始化顺序为依次为 静态数据,继承的基类的构造函数,成员变量,被调用的构造函数. ...
- Java类加载器加载类顺序
java ClassLoader的学习 java是一门解释执行的语言,由开发人员编写好的java源文件先编译成字节码文件.class形式,然后由java虚拟机(JVM)解释执 行,.class字节码文 ...
- Java父类与子类方法调用顺序
父类 FatherClass package 父类与子类方法调用顺序; /** * 父类 * @author shundong * */ public class FatherClass { priv ...
- java类加载机制及方法调用
类加载机制 概述 类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载(Loading).验证(Verification).准备(Preparation).解析(Resoluti ...
- Java 类的构造器的调用顺序
规则如下: 对于一个复杂的对象,构建器的调用遵照下面的顺序: (1) 调用父类构建器.这个步骤会不断重复下去,首先得到构建的是分级结构的根部,然后是下一个子类,等等.直到抵达最深一层的子类. (2) ...
- java和C#实例化类初始化顺序
c# 初始化顺序 子类的静态字段 子类的静态构造方法 子类的实例字段 父类的静态字段 父类的静态构造方法 父类的实例字段 父类的实例构造方法 java 初始化顺序 初始化过程: 1. 初始化父类中的静 ...
- java实例变量及方法调用顺序
public class Base { private String name="base"; public Base(){ sayHello(); } void sayHello ...
- java 实例化是调用了子类重写方法
java 实例化时调用了抽象方法或者class里面某个方法,如果子类有重写改方法,实际运行的是子类重写方法 package auto.test; //抽象父类 public abstract clas ...
- Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序
当创建一个对象时,各种成员变量及构造方法的初始化或调用顺序是怎样的呢? (1).如果类尚未加载,则先初始化静态成员变量和静态代码块,再初始化成员变量,最后调用相应的构造方法: (2).如果类已经加载过 ...
随机推荐
- 软件安装——internal error2503/2502
安装新的软件后先报internal error 2503,随后报internal error 2502.就是不让我装新的软件,提示说发生严重错误,然后安装失败. Solution for intern ...
- Java——容器(Set)
[Set接口] <1>Set接口是Collection的子接口,Set接口没有提供额外的方法. <2>实现Set接口的容器类中的元素是没有顺序的,而且不可以重复. <3& ...
- 基于BootStrap的分页代码实现
public class PageUtil { //targetUrl 访问url totalNum总记录数 currentPage 当前页数 pageSize每页的大小 public static ...
- WEB Fuzz中需要关注的7种响应
WEB应用模糊测试(WEB Fuzz)是一种特殊形式的网络协议模糊测试,专门关注遵循HTTP规范的网络数据包. WEB Fuzz并不是新的概念,目前有多种WEB应用模糊测试器(WEB Fuzzer), ...
- SQL 批量修改一个字段的值为另一个字段的值
AND create_time BETWEEN '2016-07-25 14:30:00' AND '2016-07-25 15:20:28'; AND create_time BETWEEN '20 ...
- Xcode磁盘空间清理
http://www.iwangke.me/2013/09/09/clean-xcode-to-free-up-disk-space/#jtss-tsina 这个目录下面的文件也可以隔一段儿时间清理一 ...
- JavaScript export
export The export statement is used when creating JavaScript modules to export functions, objects, o ...
- Intellij IDEA中使用Debug调试详解
转载:https://www.linuxidc.com/Linux/2017-09/146772.htm Intellij IDEA中使用Debug调试详解 Debug用来追踪代码的运行流程,通常 ...
- R 时间戳转化
转 http://stackoverflow.com/questions/1962278/dealing-with-timestamps-in-r You want the (standard) PO ...
- python修改文件
文档username.txt 将文件中密码123456改成67890: 方法一:(简单粗暴) 1.打开文件 2.读出数据 3.修改数据 4.清空原来文件,将新的内容写进去 f = open('user ...