这篇文章主要讲解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初始化过程的更多相关文章

  1. 【Java】Java初始化过程总结

    概述 Java字节代码:byte[] Java类在JVM的表现形式:Class类的对象: Java源代码被编译成class字节码 : Java字节代码 --> Class类的对象: 加载:把Ja ...

  2. (原)Java初始化过程

    先看一个demo,然后进行归纳. class X{ static M m=new M(); Y y=new Y(); public X(){ System.out.print("X" ...

  3. java初始化过程中成员变量

    package day01; class Base{ int j; //1.j=0 Base(){ add(1); //2.调用子类add()方法 System.out.println(j); //4 ...

  4. AJPFX总结Java 程序初始化过程

    觉得Core Java在Java 初始化过程的总体顺序没有讲,只是说了构造器时的顺序,作者似乎认为路径很多,列出来比较混乱.我觉得还是要搞清楚它的过程比较好.所以现在结合我的学习经验写出具体过程: 过 ...

  5. Java类变量和成员变量初始化过程

    一.类的初始化 对于类的初始化:类的初始化一般只初始化一次,类的初始化主要是初始化静态成员变量. 类的编译决定了类的初始化过程. 编译器生成的class文件主要对定义在源文件中的类进行了如下的更改: ...

  6. java代码的初始化过程研究

        刚刚在ITeye上看到一篇关于java代码初始化的文章,看到代码我试着推理了下结果,虽然是大学时代学的知识了,没想到还能做对.(看来自己大学时掌握的基础还算不错,(*^__^*) 嘻嘻……)但 ...

  7. java中对象产生初始化过程

    以前面试的时候,很多公司的笔试题中有关new一个对象有关一系列初始化的过程的选择题目.请看下面的题目. class Parent { static { System.out.println(" ...

  8. 解析Java类和对象的初始化过程

    类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来 ...

  9. 【Thinking in Java】类和对象的初始化过程

    在Java中, 当一个类被调用的时候,它的初始化过程是怎么样的呢? 当一个类被实例化的时候,它的初始化过程又是怎样的呢? 为什么static方法不能未经对象就调用非static方法? 下面我们通过例子 ...

随机推荐

  1. JavaScript动画-拖拽改变元素大小

    ▓▓▓▓▓▓ 大致介绍 拖拽改变元素大小是在模拟拖拽上增加了一些功能 效果:拖拽改变元素大小 ▓▓▓▓▓▓ 拖拽改变元素大小原理 首先这个方块得知道我们想要改变这个它的大小,所以我给它设定一个范围,当 ...

  2. 从零开始编写自己的C#框架(28)——建模、架构与框架

    文章写到这里,我一直在犹豫是继续写针对中小型框架的设计还是写些框架设计上的进阶方面的内容?对于中小型系统来说,只要将前面的内容进行一下细化,写上二三十章具体开发上的细节,来说明这个通用框架怎么开发的就 ...

  3. ASP.NET Core 1.0 使用 Dapper 操作 MySql(包含事务)

    操作 MySql 数据库使用MySql.Data程序包(MySql 开发,其他第三方可能会有些问题). project.json 代码: { "version": "1. ...

  4. .NET跨平台之运行与Linux上的Jexus服务器

    谈及.NET跨平台,已经不是什么稀奇的事儿.今天我们就以Jexus服务器的部署为例.简单示范下.在这里,我用VMWare虚拟机来搭建Linux运行环境. Linux,我们选择CentOS7.大家可以前 ...

  5. C# 索引器,实现IEnumerable接口的GetEnumerator()方法

    当自定义类需要实现索引时,可以在类中实现索引器. 用Table作为例子,Table由多个Row组成,Row由多个Cell组成, 我们需要实现自定义的table[0],row[0] 索引器定义格式为 [ ...

  6. [转载]一个标准java程序员的进阶过程

    第一阶段:Java程序员 技术名称 内                 容 说明 Java语法基础 基本语法.数组.类.继承.多态.抽象类.接口.object对象.常用类(Math\Arrarys\S ...

  7. Linux实战教学笔记02:计算机系统硬件核心知识

    标签(空格分隔):Linux实战教学笔记-陈思齐 第1章 互联网企业常见服务器介绍 1.1 互联网公司服务器品牌 - DELL(大多数公司,常用) - HP - IBM(百度在用) 浪潮 联想 航天联 ...

  8. ubuntu-14.04-server配置Jexus --安装步骤记录

    作者:郝喜路   个人主页:http://www.cnicode.com      博客地址:http://haoxilu.cnblogs.com 说明:我是Linux菜鸟,自己尝试配置Jexus服务 ...

  9. 针对Linux ASP.NET MVC网站中 httpHandlers配置无效的解决方案

    近期有Linux ASP.NET用户反映,在MVC网站的Web.config中添加 httpHandlers 配置用于处理自定义类型,但是在运行中并没有产生预期的效果,服务器返回了404(找不到网页) ...

  10. RabbitMQ的安装过程

    原创文章转载请注明出处:@协思, http://zeeman.cnblogs.com 网上一些安装教程都较为繁琐,实际上只需要两个RPM包,几分钟即可完成一台实例部署. 准备下载Erlang包: ht ...