Java 类的实例化过程

写在前面的话:

一个培训出来的朋友找工作,遇到了关于"类的实例化创建过程"的笔试题,一脸懵逼的问我,一番了解后,发现培训学校只会发笔试题,并不会详细讲解类的实例化过程(并非diss培训机构,估摸着是这货没认真听),故有此文,给自己,也给所有初学java的朋友们。

本文将从 概念 + 例题(若干) 的形式,讲解类的实例化过程。

                                                                                             ——万丈高楼平地起,勿以浮沙筑高台。



一、概念篇

1、关于static:

答:书上说,static指“静态的”。可理解为“全局的”,如:全局的属性,全局的方法,全局的代码块。

     1)全局的属性、全局的方法:即这个类所有的对象都共有的属性和方法。因为类是共有的,所有可声明直接调用。因此,也可理解为“单例模式”的属性和方法。何为单例模式?这个类声明的所有对象都共享这些属性和方法,一个对象对这个属性做了修改,那么所有的对象再次调用这个属性,就都是修改后的值了。

     2)全局的代码块:随着类的加载而执行,且只执行一次。

 

2、类的实例化过程:

答:1)给对象分配空间,对属性类型进行默认初始化。(8种基本数据类型,均按照默认方式初始化,其他数据类型默认为null)

        2)加载父类静态代码块

        3)加载本类静态代码块

        4)加载子类静态代码块

        5)初始化父类属性

        6)初始化父类构造代码块

        7)初始化父类构造方法

        8)初始化本类属性。

        9)初始化本类构造代码块

        10)初始化本类构造方法

        11)初始化子类属性

        12)初始化子类构造代码块

        13)初始化子类构造方法

以上可总结为3点:对象空间的分配,属性默认初始化 ---> 静态代码块初始化 ---> 属性、构造代码块、构造方法初始化(哪个写在前面先初始化哪个)

 

二、例题篇

1、爷 --> 父 --> 子:

1)代码如下,要求列出结果:

/****************************************************
 *
 * 爷类
 *
 *
 * @author Francis
 * @date 2019/8/21 13:57
 * @version 1.0
 **************************************************/
public class GrandParent {
    int num = 25;

    static {
        System.out.println("爷类静态代码块");
        System.out.println();
    }

    {
        System.out.println("爷类构造代码块1," + num);
        num = 21;
        System.out.println("爷类构造代码块2," + num);
        doSomething();
        System.out.println();
    }

    GrandParent() {
        System.out.println("爷类构造方法1," + num);
        num = 32;
        System.out.println("爷类构造方法2," + num);
        doSomething();
        System.out.println();
    }

    void doSomething() {
        System.out.println("爷类doSomething方法1," + num);
        num = 33;
        System.out.println("爷类doSomething方法2," + num);
        System.out.println();
    }
}
/****************************************************
 *
 * 父类
 *
 *
 * @author Francis
 * @date 2019/8/21 13:46
 * @version 1.0
 **************************************************/
public class Parent extends GrandParent{
    int num = 5;

    static {
        System.out.println("父类静态代码块");
        System.out.println();
    }

    {
        System.out.println("父类构造代码块1," + num);
        num = 1;
        System.out.println("父类构造代码块2," + num);
        doSomething();
        System.out.println();
    }

    Parent() {
        System.out.println("父类构造方法1," + num);
        num = 2;
        System.out.println("父类构造方法2," + num);
        doSomething();
        System.out.println();
    }

    void doSomething() {
        System.out.println("父类doSomething方法1," + num);
        num = 3;
        System.out.println("父类doSomething方法2," + num);
        System.out.println();
    }
}
/****************************************************
 *
 * 子类
 *
 *
 * @author Francis
 * @date 2019/8/21 13:47
 * @version 1.0
 **************************************************/
public class Child extends Parent{

    int num = 10;

    /*
        静态代码块,在类加载时执行
    */
    static {
        System.out.println("子类静态代码块");
        System.out.println();
    }

    /*
        构造代码块
    */
    {
        System.out.println("子类构造代码块1," + num);
        num = 11;
        System.out.println("子类构造代码块2," + num);
        doSomething();
        System.out.println();
    }

    Child() {
        System.out.println("子类构造方法1," + num);
        num = 12;
        System.out.println("子类构造方法2," + num);
        doSomething();
        System.out.println();
    }

    void doSomething() {
        System.out.println("子类doSomething方法1," + num);
        num = 13;
        System.out.println("子类doSomething方法2," + num);
        System.out.println();
    }

}
/****************************************************
 *
 * 测试类的实例化过程
 *
 *
 * @author Francis
 * @date 2019/8/21 13:49
 * @version 1.0
 **************************************************/
public class TempTest extends DemoApplicationTests{

    @Test
    public void method1(){
        Child child = new Child();
        child.num = 20;
        child.doSomething();
    }
}

2)过程解析(此处仅分析 Child child = new Child() 这一行代码,对child.num = 20; child.doSomething()不做说明。)

    a)对象属性初始化,Child类的num属性初始化值为0。(对应  c)中出现的doSomething方法,0 )

    b)加载静态代码块,以 爷 --> 父 --> 子的顺序,故依次输出:

爷类静态代码块

父类静态代码块

子类静态代码块

    c)加载构造代码块、构造方法,以 爷 --> 父 --> 子的顺序输出。另,因此处是对Child类进行实例化,故doSomething方法调用的是Child类的。故依次输出:

爷类构造代码块1,25
爷类构造代码块2,21
子类doSomething方法1,0
子类doSomething方法2,13


爷类构造方法1,21
爷类构造方法2,32
子类doSomething方法1,13
子类doSomething方法2,13


父类构造代码块1,5
父类构造代码块2,1
子类doSomething方法1,13
子类doSomething方法2,13


父类构造方法1,1
父类构造方法2,2
子类doSomething方法1,13
子类doSomething方法2,13


子类构造代码块1,10
子类构造代码块2,11
子类doSomething方法1,11
子类doSomething方法2,13


子类构造方法1,13
子类构造方法2,12
子类doSomething方法1,12
子类doSomething方法2,13


3)完整结果输出如下所示:

------------------------测试开始------------------------
爷类静态代码块

父类静态代码块

子类静态代码块

爷类构造代码块1,25
爷类构造代码块2,21
子类doSomething方法1,0
子类doSomething方法2,13


爷类构造方法1,21
爷类构造方法2,32
子类doSomething方法1,13
子类doSomething方法2,13


父类构造代码块1,5
父类构造代码块2,1
子类doSomething方法1,13
子类doSomething方法2,13


父类构造方法1,1
父类构造方法2,2
子类doSomething方法1,13
子类doSomething方法2,13


子类构造代码块1,10
子类构造代码块2,11
子类doSomething方法1,11
子类doSomething方法2,13


子类构造方法1,13
子类构造方法2,12
子类doSomething方法1,12
子类doSomething方法2,13


子类doSomething方法1,20
子类doSomething方法2,13

------------------------测试结束------------------------

 

 

2、爷 --> 父 --> 子,其他:

1)代码如下,要求列出输出结果:

/**
 * 父类
 */
public class Parent extends GrandParents{

    OtherClass other = new OtherClass();

    static {
        System.out.println("static code : parent");
    }

    {
        System.out.println("Parent 构造代码块");
    }

    Parent() {
        System.out.println("parent");
    }

    public static void main(String[] args) {
        new Child();
    }
}


/**
 * 不相干的其他类
 */
class OtherClass {
    OtherClass() {
        System.out.println("Other Class");
    }
}


/**
 * 子类
 */
class Child extends Parent {
    OtherClass other = new OtherClass();

    static {
        System.out.println("static code : child");
    }

    Child() {
        System.out.println("child");
    }
}


/**
 * 爷类
 */
class GrandParents{

    static {
        System.out.println("static code : grandParents");
    }

    {
        System.out.println("grandParents 构造代码块");
    }

    GrandParents(){
        System.out.println("GrandParents");
    }

}

 

2)过程分析:

    a.main()方法在Parent类中,故要执行main()方法,需要将Parent类加载到内存中,即会先执行Parent类的“静态属性”和“静态代码块”。根据概念2所提到的,因Parent存在父类GrandParents,故此时实际是先执行GrandParrents静态代码块,再执行Parent静态代码块。所以输出如下所示:

static code : grandParents
static code : parent

    b.初始化完成,执行main()方法,此时执行new Child()。

    c.根据例题1,可知,此时应按照 爷 --> 父 --> 子 的顺序加载静态代码块。但由于GrandParent和Parent的静态代码块已经执行过一次,故此处仅执行Child类的静态代码块(参考概念1中第二点)。故此处输出如下所示:

static code : child

    d.初始化属性,加载构造代码块、构造方法(以 爷 --> 父 -->  子的顺序),对于爷类来说,此处输出2行代码;对于父类来说,此处初始化属性调用了new OtherClass(),故会先执行OtherClass中的构造方法,再执行父类的构造代码块、构造方法,此处输出3行代码;子类同理(输出2行代码)。【注:属性、构造代码块、构造方法,哪个写在前面,先执行哪个。概念中已对此点做过说明。】输出结果如下所示:

grandParents 构造代码块
GrandParents
Other Class
Parent 构造代码块
parent
Other Class
child

 3)完整结果如下所示:

static code : grandParents
static code : parent
static code : child
grandParents 构造代码块
GrandParents
Other Class
Parent 构造代码块
parent
Other Class
child

 

 

三、结论篇

1、实例化过程(按 爷 --> 父 --> 子的顺序):对象空间的分配,属性默认初始化 ---> 静态代码块初始化 ---> 属性、构造代码块、构造方法初始化(哪个写在前面先初始化哪个)

2、以上例题中刻意忽略了括号中的内容:哪个写在前面先初始化哪个。有兴趣的可自行测试。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值