java程序员应该知道的对象实例化顺序

原创
2013/10/14 22:27
阅读数 333

    可能学过java的人都应该知道类的继承,子类总是先执行父类的构造方法,然后再执行本类的构造方法来实例化对象,下面我们先来看一个例子来体现这一规则:

class Test 
{
	public static void main(String[] args) 
	{
		B b = new B();
	}
}
// 父类
class A
{
	public A()
	{
		System.out.println("父类的构造函数...");
	}
}
// 子类
class B extends A
{
	public B()
	{
		System.out.println("本类的构造函数...");
	}
}
大家一定会想,这么简单的一个程序算什么呢,大家应该都能分析出来答案了


父类的构造函数...
本类的构造函数...
这就反映了先父类的构造->本类的构造的执行顺序;


那现在大家再用这个思路来分析这个看似简单,实际暗藏了些许陷阱的几十行代码:

class Test 
{
    public static void main(String[] args) 
    {
        A a = new B();
    }
}

class A
{
    int age = 11;
    {
        System.out.print(age + " ");
        age = 22;
        System.out.print(1 + " ");
    }

    public A()
    {
        System.out.print(2 + " ");
        printAge();
    }

    public void printAge()
    {
        System.out.print(this.age + " ");
    }
}

class B extends A
{
    int age = 3;// {}初始化块
    {
        System.out.print(3 + " ");
    }

    public B()
    {
        System.out.print(4 + " ");
        printAge();
    }

    public void printAge()
    {
        System.out.print(this.age + " ");
    }
}


大家先来分析一下上面这个代码会输出什么?


首先我们先来看看正确的输出结果,再来分析其缘由;正确的结果如下:

11 1 2 0 3 4 3

怎么样,大家分析结果正确了吗?或者是否会对这个结果有怀疑呢,不用怀疑,将这个程序段复制运行一下你将会看到这个可爱的结果了;

那为什么结果是这样呢?现在我就带大家一起来分析一下这段代码,分析完之后你将会对 对象实例化顺序有一个新的认识;

分析之前我先大家说一下对象实例化的几个基本顺序:

  1. 给父类和子类的成员变量分配内存空间,并初始化值(这里涉及基本数据类型的默认值的知识,在这里就不细说了);
  2. 执行父类的成员变量声明和初始化块(顺序执行)
  3. 执行父类的构造函数(具体执行哪个构造函数是由子类的构造函数决定的)
  4. 执行子类的成员变量声明和初始化块(也是顺序执行)
  5. 最后才是子类的构造函数的执行

好了,现在我们顺着这个步骤来分析一下这段代码,你清楚答案为什么是这个了:

  1. 给父类 A 和子类 B 的 age 成员分配内存空间,由于 age 是 int 类型,所以默认值都是 0 ,内存变化图如下:
  2. 执行父类的成员变量声明和初始化块(顺序执行)
        int age = 11;// 内存空间中父类的age值变为 22
        {
            System.out.print(age + " "); // 这时输出 11
            age = 22; // 内存空间中父类的age值变为 22
            System.out.print(1 + " ");// 输出 1 
        }
    执行完上面的语句之后内存最后的情况如下:
             子类的age依然是 0
    这时输出的值是:
    11 1
  3. 执行父类 A 的构造函数(具体执行哪个构造函数是由子类的构造函数决定的)
        public A()
        {
            System.out.print(2 + " ");// 会输出 2
            printAge();// 因为这个函数在子类中被重写了,所以实际执行的是子类的那个方法,输出的是子类的 age 值,而此时子类 age 的值从刚才的内存中可以看出是:0
        }
    这时输出的值是:
    11 1 2 0 
  4. 执行子类 B 的成员变量声明和初始化块(也是顺序执行)
        int age = 3;// 子类的 age 变为 3 
        {
            System.out.print(3 + " "); // 输出 3 
        }
    内存变化如下:


    这时输出的值是:
    11 1 2 0 3
  5. 执行子类 B 的构造函数
        public B()
        {
            System.out.print(4 + " "); // 输出 4 
            printAge(); // 调用子类的方法,输出子类 B 的 age 值,这是 age 的值是 3,所以输出 3 
        }
    所以最后的结果是:
    11 1 2 0 3 4 3

好了,现在时间点是 22:22,是时候洗澡去了,今天的培训笔记就先总结到这里吧!

不知道大家看完我总结的这篇笔记如何,我自己在听这个知识点的时候也是一脸的迷茫,怎么会这样的结果呢,最后一听内存变化的分析结果之后,就一切都明了啦;

所以看来自己还是不是很清楚对象的时候化顺序的,希望这个分析对大家有所收获。


总结的不好或者不对的地方,还请各位指出,学习是一个交流互动的过程,每个人看到的角度有时候确实挺大的,所以有时候会发现不一样的东西。

更多的JAVA学习总结,求关注我的每日笔记总结。bye!

展开阅读全文
加载中
点击加入讨论🔥(3) 发布并加入讨论🔥
3 评论
4 收藏
0
分享
返回顶部
顶部