先来运行一段代码

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. BZOJ 1449: [JSOI2009]球队收益 最小费用最大流 网络流

    https://www.lydsy.com/JudgeOnline/problem.php?id=1449 给每条路加上一个权值,每条路的费用是这条路的流量*权值,求最大流的最小费用. 每次spfa记 ...

  2. 【20181031T2】几串字符【数位DP思想+组合数】

    题面 [错解] 一眼数位DP 设\(f(i,c00,c01,c10,c11)\)-- 神tm DP 哎好像每两位就一定对应c中的一个,那不用记完 所以可以设\(f(i,c00,c01,c10)\)-- ...

  3. hdu 3864 素数分解

    题意:求n是否只有4个因子,如果是就输出除1外的所有因子. 模板题,就不排版了 #include<cstdio> #include<iostream> #include< ...

  4. Linux重新学习

    一.由来 unix到minix到linux 1991正式发行 1.内核版本:linux核心版本 linux内核官网www.kernel.org 2.发行版本:比如redhat.centOS.suse. ...

  5. Linux性能监控分析命令(五)—free命令介绍

    性能监控分析的命令包括如下:1.vmstat2.sar3.iostat4.top5.free6.uptime7.netstat8.ps9.strace10.lsof 命令介绍:free命令是监控Lin ...

  6. 你的C/C++程序为什么无法运行?揭秘Segmentation fault (1)

    什么让你对C/C++如此恐惧? 晦涩的语法?还是优秀IDE的欠缺? 我想那都不是问题,最多的可能是一个类似这样的错误: 段错误(Segmentation fault) 这是新手无法避免的错误,也是老手 ...

  7. Android 5.0 源代码结构

    本节书摘来自异步社区<深入理解Android 5 源代码>一书中的第2章,第2.2节分析Android源代码结构,作者 李骏. 网址:https://yq.aliyun.com/artic ...

  8. ORA-06502: PL/SQL: 数字或值错误 : 字符串缓冲区太小解决办法

    1.今天写的存储过程在执行过程中,报如下错误. exec PRO_T_008pro_update_add_delete(17,1,1,1,1,45.0,54.0,45.0,45.0,45.0,54.0 ...

  9. Java工程师成神之路 转

      一.基础篇 1.1 JVM 1.1.1. Java内存模型,Java内存管理,Java堆和栈,垃圾回收 http://www.jcp.org/en/jsr/detail?id=133 http:/ ...

  10. Eclipse批量替换

    情景: 我需要将项目中所有有"上样板"的字样替换为"PCR板",如果寻找单个页面肯定是很麻烦,而且替换很有可能不全,那么该怎么才能完全替换呢? 解决方法: ec ...