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

Wesley13
• 阅读 581

    可能学过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!

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
java成员变量的初始化
类变量(static变量,不需要实例化对象也可以引用)实例变量(非static变量,需要实例化对象)局部变量(类的成员函数中的变量)初始化方式:构造函数初始化变量声明时初始化代码块初始化java自动初始化(在构造函数执行之前执行) java保证所有变量被使用之前都是经过初始化的(声明并且定义过,被赋值
Jacquelyn38 Jacquelyn38
3年前
你不可不知的JS面试题(第二期)
1、什么是继承?子类可以使用父类的所有功能,并且对功能进行扩展。新增方法改用方法(1)、ES6使用extends子类继承父类的方法。// 父类    class A        constructor(name)            this.name name;                getNa
Wesley13 Wesley13
3年前
Java日期时间API系列31
  时间戳是指格林威治时间1970年01月01日00时00分00秒起至现在的总毫秒数,是所有时间的基础,其他时间可以通过时间戳转换得到。Java中本来已经有相关获取时间戳的方法,Java8后增加新的类Instant等专用于处理时间戳问题。 1获取时间戳的方法和性能对比1.1获取时间戳方法Java8以前
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Wesley13 Wesley13
3年前
Java日期时间API系列30
  实际使用中,经常需要使用不同精确度的Date,比如保留到天2020042300:00:00,保留到小时,保留到分钟,保留到秒等,常见的方法是通过格式化到指定精确度(比如:yyyyMMdd),然后再解析为Date。Java8中可以用更多的方法来实现这个需求,下面使用三种方法:使用Format方法、 使用Of方法和使用With方法,性能对比,使用
Wesley13 Wesley13
3年前
unity将 -u4E00 这种 编码 转汉字 方法
 unity中直接使用 JsonMapper.ToJson(对象),取到的字符串,里面汉字可能是\\u4E00类似这种其实也不用转,服务器会通过类似fastjson发序列化的方式,将json转对象,获取对象的值就是中文但是有时服务器要求将传参中字符串中类似\\u4E00这种转汉字,就需要下面 publ
Python进阶者 Python进阶者
10个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
小万哥 小万哥
9个月前
Java 构造函数与修饰符详解:初始化对象与控制权限
Java构造函数Java构造函数是一种特殊的类方法,用于在创建对象时初始化对象的属性。它与类名相同,并且没有返回值类型。构造函数的作用:为对象的属性设置初始值执行必要的初始化操作提供创建对象的多种方式构造函数的类型:默认构造函数:无参数的构造函数,如果用户