Java初始化过程
这篇文章主要讲解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】Java初始化过程总结
概述 Java字节代码:byte[] Java类在JVM的表现形式:Class类的对象: Java源代码被编译成class字节码 : Java字节代码 --> Class类的对象: 加载:把Ja ...
- (原)Java初始化过程
先看一个demo,然后进行归纳. class X{ static M m=new M(); Y y=new Y(); public X(){ System.out.print("X" ...
- java初始化过程中成员变量
package day01; class Base{ int j; //1.j=0 Base(){ add(1); //2.调用子类add()方法 System.out.println(j); //4 ...
- AJPFX总结Java 程序初始化过程
觉得Core Java在Java 初始化过程的总体顺序没有讲,只是说了构造器时的顺序,作者似乎认为路径很多,列出来比较混乱.我觉得还是要搞清楚它的过程比较好.所以现在结合我的学习经验写出具体过程: 过 ...
- Java类变量和成员变量初始化过程
一.类的初始化 对于类的初始化:类的初始化一般只初始化一次,类的初始化主要是初始化静态成员变量. 类的编译决定了类的初始化过程. 编译器生成的class文件主要对定义在源文件中的类进行了如下的更改: ...
- java代码的初始化过程研究
刚刚在ITeye上看到一篇关于java代码初始化的文章,看到代码我试着推理了下结果,虽然是大学时代学的知识了,没想到还能做对.(看来自己大学时掌握的基础还算不错,(*^__^*) 嘻嘻……)但 ...
- java中对象产生初始化过程
以前面试的时候,很多公司的笔试题中有关new一个对象有关一系列初始化的过程的选择题目.请看下面的题目. class Parent { static { System.out.println(" ...
- 解析Java类和对象的初始化过程
类的初始化和对象初始化是 JVM 管理的类型生命周期中非常重要的两个环节,Google 了一遍网络,有关类装载机制的文章倒是不少,然而类初始化和对象初始化的文章并不多,特别是从字节码和 JVM 层次来 ...
- 【Thinking in Java】类和对象的初始化过程
在Java中, 当一个类被调用的时候,它的初始化过程是怎么样的呢? 当一个类被实例化的时候,它的初始化过程又是怎样的呢? 为什么static方法不能未经对象就调用非static方法? 下面我们通过例子 ...
随机推荐
- 如何一步一步用DDD设计一个电商网站(七)—— 实现售价上下文
阅读目录 前言 明确业务细节 建模 实现 结语 一.前言 上一篇我们已经确立的购买上下文和销售上下文的交互方式,传送门在此:http://www.cnblogs.com/Zachary-Fan/p/D ...
- 关于开启.NET在线提升教育培训的通知! - 可在此页面观看在线直播!
年前在线公开课程通知: 近期在开启VIP课程,隔天讲一次,年前其它时间插空讲公开课,主题:设计模式系列 1:培训 - 大概不会讲的内容: 1:不讲系列. 2:不讲入门. 3:不讲我不懂的! 2:培训 ...
- 快速搭建springmvc+spring data jpa工程
一.前言 这里简单讲述一下如何快速使用springmvc和spring data jpa搭建后台开发工程,并提供了一个简单的demo作为参考. 二.创建maven工程 http://www.cnblo ...
- SQL Server-聚焦计算列持久化(二十一)
前言 上一节我们结束了Hash Match Aggregate和Stream Aggregate的讲解,本系列我们来讲讲关于SQL Server中的计算列问题,简短的内容,深入的理解,Always t ...
- UWP开发之Mvvmlight实践七:如何查找设备(Mobile模拟器、实体手机、PC)中应用的Log等文件
在开发中或者后期测试乃至最后交付使用的时候,如果应用出问题了我们一般的做法就是查看Log文件.上章也提到了查看Log文件,这章重点讲解下如何查看Log文件?如何找到我们需要的Packages安装包目录 ...
- 云计算下PAAS的解析一
云计算下PAAS的解析一 PaaS是Platform-as-a-Service的缩写,意思是平台即服务. 把服务器平台作为一种服务提供的商业模式.通过网络进行程序提供的服务称之为SaaS( ...
- Lind.DDD.LindAspects方法拦截的介绍
回到目录 什么是LindAspects 之前写了关于Aspects的文章<Lind.DDD.Aspects通过Plugins实现方法的动态拦截~Lind里的AOP>,今天主要在设计思想上进 ...
- 《如何使用Javascript判断浏览器终端设备》
WEB开发中如何通过Javascript来判断终端为PC.IOS(iphone).Android呢? 可以通过判断浏览器的userAgent,用正则来判断手机是否是ios和Android客户端. va ...
- JavaScript基础
JavaScript基础 JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应代码之,浏览器可以解释并做出相应的处 ...
- (转)从0开始搭建SQL Server AlwaysOn 第一篇(配置域控+域用户DCADMIN)
原文地址: http://www.cnblogs.com/lyhabc/p/4678330.html 实验环境: 准备工作 软件准备 (1) SQL Server 2012 (2) Windows S ...