这篇文章主要讲解Java在创建对象的时候,初始化的顺序。主要从以下几个例子中讲解:

继承关系中初始化顺序

初始化块与构造器的顺序

已经加载过的类的初始化顺序

加载父类,会不会加载子类

创建子类对象会不会创建父类对象

例子1——继承关系中初始化顺序

先看简单的情况,看下面的例子:

public class Father {

public String fatherVar = "父类构造块初始化";

public static int fatherStaticVar;

public int i;

static {

int i = 100;

System.out.println("父类静态块初始化,i的值为" + i);

System.out.println("父类静态变量初始化,fatherStaticVar的值为" + fatherStaticVar);

}

{

System.out.println(fatherVar);

}

public Father(){

System.out.println("父类构造函数的初始化,i的值" + i);

}

}

public class Son extends Father {

public String sonVar = "子类构造块初始化";

public static int sonStaticVar;

public int i;

static {

int i = 101;

System.out.println("子类静态块初始化,i的值为" + i);

System.out.println("子类静态变量初始化,sonStaticVar的值为" + sonStaticVar);

}

{

System.out.println(sonVar);

}

public Son(){

super();

System.out.println("子类构造函数的初始化,i的值" + i);

}

public static void main(String[] args) {

new Son();

}

}

其执行的结果如下:

父类静态块初始化,i的值为100

父类静态变量初始化,fatherStaticVar的值为0

子类静态块初始化,i的值为101

子类静态变量初始化,sonStaticVar的值为0

父类构造块初始化

父类构造函数的初始化,i的值0

子类构造块初始化

子类构造函数的初始化,i的值0

按照结果,我们可以知道在有继承的时候,虽然是创建一个Son对象,但是JVM发现Son对象的类还没有装载,而Son类又继承自Father类,只有加载了Father类,才能加载Son类。于是加载Father类的时候,就会初始化一切静态变量和静态块。所以上文结果中第一行和第二行是父类静态变量和静态块初始化的结果,然后加载完Father类之后,又会加载Son类,同样是初始化Son类的静态块和静态变量,出现上文中第三行和第四行的结果。等这个2个类都加载完了,才开始创建Son对象,因为Son对象,显示调用了Father类的构造器,所以先执行Father类的构造器,出现第五行和第六行的结果,等Father类构造器执行完了,才执行后续Son构造器的内容,所以最后出现了第七行和第八行的结果。

例子2——初始化块与构造器的顺序

在上面的例子中,有2个语句块叫初始化块。在上文的结果中是初始化块的执行是先于构造器的,现在看一下把初始化块的内容放到构造器下面,会是什么的结果

public class InitBlock {

public InitBlock(){

System.out.println("构造器在执行......");

}

{

System.out.println("初始化块1在执行......");

}

{

System.out.println("初始化块2在执行......");

}

public static void main(String[] args) {

new InitBlock();

}

}

结果如下:

初始化块1在执行......

初始化块2在执行......

构造器在执行......

很显然,无论初始化块写在哪个地方,都是先于构造器执行的,但是初始化块之间的顺序是前面的先初始化,后面在初始化。

例子3——已经加载过的类的初始化顺序

更改一下例子1中的main方法,改成如下:

public static void main(String[] args) {

new Father();

System.out.println("=============");

new Son();

}

结果如下:

父类静态块初始化,i的值为100

父类静态变量初始化,fatherStaticVar的值为0

子类静态块初始化,i的值为101

子类静态变量初始化,sonStaticVar的值为0

父类构造块初始化

父类构造函数的初始化,i的值0

=============

父类构造块初始化

父类构造函数的初始化,i的值0

子类构造块初始化

子类构造函数的初始化,i的值0

结果很有意思,创建父类对象的时候,加载Father类,出现第一行和第二行的结果,但是这个竟然会还把子类的静态变量和静态块初始化?这个原因,例子4在说。 最后执行父类的构造器创建父类对象。当再创建子类的时候,发现父类和子类已经加载过了,所以不会再加载Father和Son类,只会调用父类的构造器,再执行后续子类构造器的内容,创建子类。

例子4——加载父类,会不会加载子类

用一个崭新的例子来看看上面,创建父类的时候,为什么会打印出子类静态初始化执行的结果。

public class StaticFather {

static{

System.out.println("父类静态初始化块");

}

}

public class StaticSon extends StaticFather{

static {

System.out.println("子类静态初始化块");

}

}

public class Test {

public static void main(String[] args) {

new StaticFather();

}

}

结果如下:

父类静态初始化块

这次就不会创建父类的时候,加载子类。例子3之所以出现这个原因 是因为main函数在子类中写的,要执行main函数必须要加载子类。只会加载子类之前要先加载父类,因为不加载父类,只加载子类,怎么让子类调用父类的方法和变量。但是加载父类不会加载子类,反正父类也调用不了子类的方法。

例子5——创建子类对象会不会创建父类对象

做个实验,看一下创建子类对象的时候,到底会不会创建一个父类对象,先说结论:不会。从道理上讲,如果创建任何一个对象都要创建出一个他的父类对象的话,那么整个JVM虚拟机都是Object对象。看下面的实验:

public class ObjectFather {

public void getInfo(){

System.out.println(getClass().toString());

}

}

public class ObjectSon extends ObjectFather{

public ObjectSon(){

super();

super.getInfo();

}

public static void main(String[] args) {

new ObjectSon();

}

}

结果如下:

class com.byhieg.init.ObjectSon

可以看出来,创建子类对象时那个父类的Class还是子类的,也就是说创建子类对象并没有创建一个父类的对象,只是说调用了父类的构造器,对父类的属性进行初始化,并且给子类提供了一个super指示器去调用父类中那些变量和方法。

更详细的说,new一个对象实际上是通过一个new指令开辟一个空间,来存放对象。在new ObjectSon()的时候,就只有一个new指令,只会开辟一个空间,所谓初始化父类等等,都是在这个空间中有一个特殊的区域来存放这些数据,而super关键字就是提供了访问这个特殊区域的方法,通过super去访问这个特殊区域。

还可以比较super和this的hashcode来判断,结果必然是两者的hashcode是一致的。

总结

至此,Java初始化的讲解到结束了,基本了覆盖了绝大多数情况中的初始化。

java在初始化过程_Java初始化过程相关推荐

  1. java运行过程_Java执行过程

    Java的运行原理 在Java中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器.这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口.编译程序只需要面向虚拟机,生成虚拟机能 ...

  2. java项目初期化_Java初始化规则都不懂,搞什么开发!

    这个教程,咱们来对Java中设计到的初始化规则,或者说初始化顺序,来做一下汇总,这里我基本上把Java中,默认初始化,静态成员初始化,非静态成员初始化,静态代码块,非静态代码块,以及继承中所涉及到的初 ...

  3. java在初始化过程_Java初始化和实例化顺序

    以下是在对象创建过程中打印每个步骤的顺序的示例. instance create step test.Java: import javax.annotation.PostConstruct; /** ...

  4. java 储存过程_Java储存过程

    存储过程:是指保存在数据库并在数据库端执行的程序. CallableStatement 对象为所有的 DBMS 提供了一种以标准形式调用已储存过程的方法.已储存过程储存在数据库中. 对已储存过程的调用 ...

  5. java初始化配置_java – 初始化没有XML配置的数据库,但使用@Configuration

    你的@Configuration类下面的代码行可能工作. @Value("classpath:com/foo/sql/db-schema.sql") private Resourc ...

  6. java初始化实例化_Java对象的创建过程:类的初始化与实例化

    一.Java对象创建时机 我们知道,一个对象在可以被使用之前必须要被正确地实例化.在Java代码中,有很多行为可以引起对象的创建,最为直观的一种就是使用new关键字来调用一个类的构造函数显式地创建对象 ...

  7. java类静态初始化_Java静态代码块和类初始化、实例初始化过程

    1. 静态代码块 静态代码块:定义在类中方法外,使用static修饰 ①可以为类变量(静态变量)初始化 ②静态代码块在第一次使用这个类之前执行,即在类初始化时执行,且只执行一次 ③若有多个静态代码块, ...

  8. 解析 Java 类和对象的初始化过程 由一个单态模式引出的问题谈起

    在 IBM Bluemix 云平台上开发并部署您的下一个应用. 开始您的试用 问题引入 近日我在调试一个枚举类型的解析器程序,该解析器是将数据库内一万多条枚举代码装载到缓存中,为了实现快速定位枚举代码 ...

  9. Java 父类子类的对象初始化过程

    转载自 Java 父类子类的对象初始化过程 摘要: Java基本的对象初始化过程,子类的初始化,以及涉及到父类和子类的转化时可能引起混乱的情况. 1. 基本初始化过程: 对于一个简单类的初始化过程是: ...

最新文章

  1. 如何更改远程Git存储库的URI(URL)?
  2. 解决原子性问题?你首先需要的是宏观理解
  3. java quartz 时间配置文件_Spring Quartz如何动态配置时间(3)
  4. HTML基础第六讲---表格
  5. 2017.1.19切题总结
  6. 基于CASIA-GaitDatasetB步态图像轮廓数据库的步态周期检测与步态角度特征MATLAB源码
  7. Python 标准库之 XML(下)
  8. 第三次学JAVA再学不好就吃翔(part110)--使用指定的码表读写字符
  9. 20应用统计考研复试要点(part12)--应用多元分析
  10. A Scala Tutorial for Java programmers之(一)Scala入门:Scala例子,以及如何与Java交互
  11. php做姓名隐藏,PHP只显示姓名首尾字符,隐藏中间字符并用*替换
  12. 解决 GiWiFi 普通用户无客户端无法登入
  13. asp.net mvc 之旅—— 第一站 从简单的razor入手
  14. iOS/Android React Native 配置教程
  15. 微信朋友圈评论功能的实现步骤
  16. 第7章 - 多无人机系统的协同控制 --> 无人机飞行原理
  17. 金财致远咨询有限公司莅临美和易思参观交流
  18. 迅手系统连接不到服务器,逆火快速上手.doc
  19. IP地址、网络号、主机号、网络地址、子网掩码、网关、192.168.0.1/24是什么意思
  20. NDB Cluster 基本介绍

热门文章

  1. 基于matlab的人脸五官边缘检测方法,基于MATLAB的人脸识别系统的设计
  2. ndarray的数据类型
  3. 源、更新源时容易出现的问题解决方法
  4. Android中解析XML
  5. iec61850采样协议(9-1、9-2)解析(二)
  6. deltasql 1.6.0 发布,数据库模型版本控制
  7. asp.net学习笔记·将数据库中的数据保存在EXCEL文件中
  8. C++ 11 新特性 nullptr 学习
  9. Win 驱动编程 - 内核里操作注册表
  10. 图解Oracle 12c 触发器实例