先来运行一段代码

class A {
public A() {
init();
}
public void init() {
}
public static void main(String[] args) {
B b = new B();
System.out.println("终于i的值为:" + b.i + ",j的值为:" + b.j);
}
}
class B extends A {
int i;
int j = 999;
public void init() {
System.out.println("此时A的构造方法正在调用此方法:i的值为:" + i + ",j的值为:" + j);
i = 888;
j = 111;
}
}

看看打印什么

此时A的构造方法正在调用此方法:i的值为:0,j的值为:0
终于i的值为:888,j的值为:999

假设感到非常吃惊,那么你对Java对象的构造过程还不熟悉。那么认真阅读本文将对你有非常大帮助。

先写个案例代码

public class Super {
    static long time = 10;
    static Object obj = new Object();
    int width = 100;
    static {
        time = 11;
    }
    {
        width = 110;
    }
    public Super() {
        width = 120;
    }
    public static void main(String[] args) {
        Child child = new Child();
        System.out.println("Super.time:"+Super.time);
        System.out.println("Super.obj:"+Super.obj);
        System.out.println("child.width:"+child.width);
        System.out.println("Child.age:"+Child.age);
        System.out.println("Child.str:"+Child.str);
        System.out.println("child.height:"+child.height);
    }
}
class Child extends Super {
    static int age = 20;
    static String str = "str";
    double height = 200;
    static {
        age = 22;
    }
    {
        height = 210;
    }
    public Child() {
        height = 220;
    }
}

打印

Super.time:11
Super.obj:java.lang.Object@659e0bfd
child.width:120
Child.age:22
Child.str:str
child.height:220.0

Java中一个对象的构造过程

1.用类载入器载入父类。按父类静态变量定义的顺序的为父类全部静态变量分配空间,并赋予父类静态变量默认值

public class Super {
static long time=10;//此时time=0
static Object obj=new Object();//此时obj=null

2.用类载入器载入自己,按自己静态变量定义的顺序的为自己全部静态变量分配空间,并赋予自己静态变量默认值

class Child extends Super{
static int age=20;//此时age=0
static String str="str";//此时str=null

3.按父类静态变量定义的顺序的为父类全部静态变量赋上定义的值

public class Super {
static long time=10;//此时time=10
static Object obj=new Object();//此时obj=new Object()

4.运行父类静态代码块

public class Super {
static long time=10;
static Object obj=new Object();
int width=100;
static{
time=11;//静态代码块运行了。这个时候time=11
}

5.按自己静态变量定义的顺序的为自己全部静态变量赋上定义的值

class Child extends Super{
static int age=20;//此时age=20
static String str="str";//此时str="str"

6.运行自己静态代码块

class Child extends Super{
static int age=20;
static String str="str";
double height=200;
static{
age=22;//此时age=22
}

7.为父类实例变量分配空间。并赋予默认值

public class Super {
static long time=10;
static Object obj=new Object();
int width=100;//此时width=0

8.为自己实例变量分配空间。并赋予默认值

class Child extends Super{
static int age=20;
static String str="str";
double height=200;//此时height=0.0

9.按父类实例变量定义的顺序的为父类全部实例变量赋上定义的值

public class Super {
static long time=10;
static Object obj=new Object();
int width=100;//此时width=100

10.运行父类的构造代码块

public class Super {
static long time=10;
static Object obj=new Object();
int width=100;
static{
time=11;
}
{
width=110;//此时width=110
}

11.运行父类的构造方法

public class Super {
static long time=10;
static Object obj=new Object();
int width=100;
static{
time=11;
}
{
width=110;
}
public Super() {
width=120;//此时width=120
}

12.按自己实例变量定义的顺序的为自己全部实例变量赋上定义的值

class Child extends Super{
static int age=20;
static String str="str";
double height=200;//此时height=200.0

13.运行自己的构造代码块

class Child extends Super{
static int age=20;
static String str="str";
double height=200;
static{
age=22;
}
{
height=210;//此时height=210.0
}

14.运行自己的构造方法

class Child extends Super{
static int age=20;
static String str="str";
double height=200;
static{
age=22;
}
{
height=210;
}
public Child() {
height=220;//此时height=220.0
}

对象构造完毕!

注意

1-6属于初始化静态部分,7-14属于初始化实例部分

假设一个类的静态部分已经初始化了(已经被类载入器载入了)。就不会再反复初始化静态部分,静态部分的初始化仅仅会在类载入器载入一个类的时候初始化一次

父类假设还有父类就也按照此顺序先初始化父类的父类,直到Object为止

假设运行步骤3,5,9,12赋值操作时,假设发现所赋的值的类还没有初始化,则会先初始化那个引用的类,假设引用的类还有引用的类则也依照此顺序先初始化引用类的引用类。直到所有被引用的类所有被初始化完成为止

比如:

我们在A类中定义一个B类的引用。

public class Super {
public static void main(String[] args) {
new A();new B();
}
}
class A{
static B b=new B();//这句代码会导致B类会比A类先初始化完毕,也就是说B的静态属性会先赋值,静态代码块会先运行。
static {
System.out.println("AA");
}
}
class B{
static {
System.out.println("BB");
}
}

打印:

BB
AA

仅仅定义一个类的引用,而没有赋值,那么不会触发一个类初始化

public class Super {
public static void main(String[] args) {
new A();
}
}
class A{
static B b;
static {
System.out.println("AA");
}
}
class B{
static {
System.out.println("BB");
}
}

打印:

AA

仅仅有触发了主动使用才会导致所引用的类被初始化.

关于一个人在什么情况才算是主动使用请查看我的还有一篇文章:

http://blog.csdn.net/u012643122/article/details/46522345

假设一个类A的所引用的类B里又引用了类A,也就是递归引用的情况,那么会实施java消除递归机制

public class Super {
public static void main(String[] args) {
new A();
}
}
class A{
static B b=new B();
static {
System.out.println("AA");
}
}
class B{
static A a=new A();
static {
System.out.println("BB");
}
}

打印

BB
AA

初始化引用的类时就像走一条路,java避免递归的机制就是不走之前已经走过的地方.

假设在运行3、5、9、12时。发现变量仅仅定义了引用而没有赋值操作,那么该变量将保持默认值

如:

static long time;//保持之前所赋的默认值0
Child child;//保持之前所赋的默认值null

特殊情况可省略的步骤

假设一个类没有父类(如Object类),则它的初始化顺序能够简化成2、5、6、8、12、13、14。

假设这个类已经被类载入器载入过了,也就是该类的静态部分已经初始化过了,那么1、2、3、4、5、6都不会运行,总的顺序能够简化为7、8、9、10、11、12、13、14。

假设这个类没有被类载入器载入,但它的父类已经被类载入器载入过了。那么总的顺序能够简化为2、5、6、7、8、9、10、11、12、13、14。

转载请标明原地址。请尊重原创,谢谢!

Java之对象构造过程的更多相关文章

  1. Java内存结构、类的初始化、及对象构造过程

    概述 网上关于该题目的文章已经很多,我觉得把它们几个关联起来讲可能更好理解一下.与其它语言一样,它在执行我们写的程序前要先分配内存空间,以便于存放代码.数据:程序的执行过程其实依然是代码的执行及数据的 ...

  2. Java的对象初始化过程

    成员变量(字段)初始化顺序 在一个类里初始化的顺序是由成员变量在类里面的定义的顺序来决定的.即使成员变量大量散布于类的各个方法定义的中间,那些成员变量仍会在调用任何方法之前得以初始化,甚至在构造函数调 ...

  3. Java中对象构造

    构造函数 作用:在构造对象的同时初始化对象.java强制要求对象 诞生同时被初始化,保证数据安全. 调用过程和机制:①申请内存,②执行构造函数的函数体,③返回对象的引用. 特点:与类同名,无返回类型, ...

  4. Java基础—对象构造

    1.重载 有些类有多个构造器.例如,可以如下构造一个空的StringBuilder对象: StringBuilder message = new StringBuilder(); 或者,可以指定一个初 ...

  5. Java中对象创建过程

    本文介绍的对象创建过程仅限于普通Java对象,不包括数组和Class对象. 1.类加载检查 虚拟机遇到一条new指令时,首先去检查该指令的参数能否在常量池中定位到一个类的符号引用,并且检查这个符号引用 ...

  6. 转:java实例化对象的过程

    学习JAVA这门面向对象的语言,实质就是不断地创建类,并把类实例化为对象并调用方法.对于初学JAVA的人总搞清楚对象是如何实例化的,假如类之间存在继承关系,那就更糊涂了.下面我们通过两个例题来说明对象 ...

  7. java实例化对象的过程

    总结以上内容,可以得到对象初始化过程:  1. 如果存在继承关系,就先父类后子类:  2 .如果在类内有静态变量和静态块,就先静态后非静态,最后才是构造函数:  3 .继承关系中,必须要父类初始化完成 ...

  8. Java中对象初始化过程

    Java为对象初始化提供了多种选项. 当new一个对象的时候,对象初始化开始: 1.首先,JVM加载类(只加载一次,所以,即使多次new对象,下面的代码也只会在第一次new的时候执行一次),此时, 静 ...

  9. .ctor,.cctor 以及 对象的构造过程

    摘要: .ctor,.cctor 以及 对象的构造过程.ctor:简述:构造函数,在类被实例化时,它会被自动调用.当C#的类被编译后,在IL代码中会出现一个名为.ctor的方法,它就是我们的构造函数, ...

随机推荐

  1. 2017-2018-1 JAVA实验站 第六、七周作业

    2017-2018-1 JAVA实验站 第六.七周作业 详情请见团队博客

  2. Tomcat启动异常 java.net.BindException: Cannot assign requested address: JVM_Bind

    从Apache官网下载的tomcat7,在MyEclipse中启动时抛出如下异常: 严重: StandardServer.await: create[localhost:8005]: java.net ...

  3. chrome --headless --disable-gpu --dump-dom http://www.python.org

    Driving Headless Chrome with Python:Python chrome --headless --disable-gpu --dump-dom http://www.pyt ...

  4. CareerCup之1.3字符串去重

    [题目] 原文: 1.3 Design an algorithm and write code to remove the duplicate characters in a string witho ...

  5. 用VC资源动态链接库解决国际化问题

    http://daixinghe.blog.163.com/blog/static/1843615920097181952979/ 随着计算机应用的普及,应用软件跨国使用越来越频繁,如何实现应用软件的 ...

  6. 精心收集整理的SQL Server 2014/2012/2008/2005/2000简体中文企业版下载地址

    经常在网上看到有同学费尽心思的找SQL server数据库各版本的下载地址,看到别人的求助贴就不自觉的想去帮助他们,但是一个一个去帮助又不太现实,毕竟个人精力有限,既然大家有需求,那么笔者就本着乐于分 ...

  7. MVC文件上传01-使用jquery异步上传并客户端验证类型和大小

    本篇体验MVC上传文件,从表单上传过渡到jquery异步上传. MVC最基本的上传文件是通过form表单提交方式 □ 前台视图部分 <% using(Html.BeginForm("F ...

  8. java string常见操作(二)

  9. IOS在一个程序中启动另一个程序

    尽管iPhone不允许同时运行两个应用程序,我们可以从自己的应用程序中启动另一个应用程序,并且可以在应用程序之间共享数据.我们可以使用UIApplication类的openURL:方法从一个应用程序来 ...

  10. ExtJS GridPanel的ColumnModel 动态加载

    var colM = "company,id,flyline"; var colMArr = colM.split(","); var colLength = ...