对象的初始化过程及其深入理解

一、什么是一个类

        在Java语言里面,类用class描述,拥有变量和函数。没有提供get或set方法的变量称之为字段。有get或者set的任意方法或全部方法的字段称之为属性。所有的类都继承自Object类,并且继承了Object类提供的class属性。
        类和对象的关系,简单说:
        类可以看成一类对象的模板,对象可以看成该类的一个具体实例。

二、子类和父类

        继承是从父类中派生出新的类,这个类称之为子类或者派生类。子类拥有父类“所有”的属性和方法,并且子类能够扩展其它特性。比如说人,人可以作为一个父类,它可以派生出子类,比如男人,男人具备了人的一切特性。并且男人还有其它特性,比如说长胡子。

        如果父类的属性或者方法是private修饰的,那么父类的属性和方法依然会被子类继承到。但是,如果父类没有提供公共的访问方法的话,那么子类将无法访问到此属性或者方法,即使子类拥有此属性或者方法。举个例子,我是潘多拉的继承人,并且我继承到了潘多拉留下的魔盒,但是潘多拉并没有提供钥匙给我,所以尽管我现在拥有了潘多拉魔盒,但是仍然不能打开盒子。这就是拥有但是不能访问的现象。

        在Java中,通常父类用private修饰的属性会提供公共的访问方法,通常是public修饰的get方法。(相当于例子中的钥匙)

三、对象的初始化过程

        加载某个类到JVM中,由第一次调用这个类的静态成员触发。而构造函数又是一种特殊的静态函数,因此new一个对象的时候,JVM虚拟机将会开始加载这个类。

        类是对象的模版,对象是类的具体实例。

        通常对象的初始化过程如下:

                步骤1:第一次调用类的构造函数创建对象,也就是说第一次调用一个类的静态成员的时候,JVM将会动态的加载这个类到JVM中。用来描述这个类信息的是一个class对象。JVM加载的就是这个class对象。如果这个类有静态代码块,那么此时静态代码块将会被执行。

                步骤2:class对象加载完毕。接下来就是将此类中所有的属性将会被设置为默认值。比如,int类型的属性的默认是 0,  boolean类型的属性默认值是false等。此步骤可以理解为“默认初始化”。

                 步骤3:接着,执行构造函数的第一行,通常都是super()。基本上每个构造函数第一行都会有一句隐式super(),它将会调用父类的构造函数。子类来自于父类,所以父类的class对象也已经被JVM加载了。根据第二步,父类中所有的属性都被“默认初始化”为默认值。如果父类是Object的话,super()执行完毕都没有什么效果。现在,根据用户的定义, 比如有int age = 22;  在内存中,经过步骤2,age默认值是“0”。步骤3的作用就是把age初始化为"22",这一步可以理解为“显示初始化”。

                步骤4:显示初始化完毕,将会调用"构造代码块"。构造代码块的作用是为这个类的每一个对象进行属性的初始化。 如果我们没有在步骤3里面为字段进行“显示初始化”,那么我们可以在“构造代码块”中为字段进行初始化。这步可以理解为“构造代码块初始化”

                步骤5:构造代码块执行完毕,就下来就是执行构造函数中剩下的语句了。

例如

/**
 * Created by jay.zhou on 2018/2/22.
 */
public class Fu {
    public int count = 1;
    static {
        System.out.println("父类的class文件被JVM加载,类中所有字段被设置为默认值,int类型的值的默认值是0");
    }

    {
        System.out.println(count);
        System.out.println("根据count的值知道,count的值被显示初始化为1");
        System.out.println("父类的构造代码块执行");
        count = 2;
        System.out.println("count的值已经被修改");
    }

    public Fu() {
        super();
        System.out.println("父类的构造函数执行");
        System.out.println(count);
    }
}

class Zi extends Fu {
    static {
        System.out.println("子类的class文件被JVM加载,类中所有字段被设置为默认值,int类型的值的默认值是0");
    }

    {
        System.out.println("子类的构造代码块执行");
    }

    public Zi() {
        super();
        System.out.println("子类的构造函数执行");
    }

    public static void main(String[] args) {
        new Zi();
    }
}
父类的class文件被JVM加载,类中所有字段被设置为默认值,int类型的值的默认值是0
子类的class文件被JVM加载,类中所有字段被设置为默认值,int类型的值的默认值是0
1
根据count的值知道,count的值被显示初始化为1
父类的构造代码块执行
count的值已经被修改
父类的构造函数执行
2
子类的构造代码块执行
子类的构造函数执行

解释:

         在main()中,调用子类的构造函数,由于构造函数是一种特殊的静态函数,将会触发JVM加载子类。子类的存在必须依附于其父类,原因在下面会解释。因此,父类与子类一样,将会被加载到JVM虚拟机中,并根据步骤1,调用它们的静态代码块。父类静态代码块优先于子类静态代码块执行,可以简单的理解,先有了爸爸才会有儿子。

         根据步骤2,此时,类Fu和类Zi,它们的属性的值都是默认值,比如Fu类中的count被设置为0。

         接着,调用 Zi类的构造函数,它的第一行是super()。那么将会执行Fu类的构造函数。Fu类继承于Object类,在Fu类的构造函数中,调用完super() 后,将不会产生任何效果。接着,根据步骤3,Fu类将会进行“显示初始化”,根据private int count = 1; Fu类属性count的值从“0”被赋值为了“1”。这一点在"构造代码块"中的打印可以证明。

         根据步骤4,此时进行“构造代码块”初始化。构造代码块能为这个类的每个对象进行初始化,然而事实上很少有人使用构造代码块初始化,基本上用的是在“构造函数中”进行初始化。

      “构造代码块”执行完毕,将会执行“构造函数初始化”,此时将会执行构造函数中进行的定义的语句。

        此时,在Zi类中的构造函数的super()语句就全部执行完毕了。Zi类将会像Fu类执行完super()语句一样,进行“显示初始化”,“构造代码块初始化”,最后执行Zi类构造函数中剩下的语句。

       综上:对象初始化过程的步骤是:

                 1.被JVM加载,执行静态代码块

                 2.默认初始化 ,  属性被赋予默认值

                 3.显示初始化,定义的时候被赋予什么值,现在就是什么值

                 4.构造代码块初始化,构造代码块中重新为属性赋予新值

                 5.最后是构造函数初始化,一锤定音的还是构造函数中赋予的值

对象的初始化过程较为复杂,如果有没有看懂的欢迎留言。

四、子类对象与父类对象的联系

        类好比一张图纸。在创建对象的过程中,子类对象根据子类的图纸,创建出来的对象,为什么它能够访问到从父类继承到的属性呢?问题是父类也是一张图纸,我们在创建子类对象的时候,并没有调用父类的构造函数,去创建一个父类对象。
比如  new Zi(); 为什么这个对象它拥有父类的count这个字段
        子类对象与父类对象的关系,如图所示。

           

           此图说明,在初始化子类对象之前,父类对象就已经被初始化完毕。

           子类对象能够访问到父类对象的属性,这说明每一个子类对象都独立的拥有一个属于它自己的父类对象

           因此,可以说,子类对象的创建必须依附于父类对象。在创建子类对象的过程中,先创建一个父类对象A,然后创建一个子类对象B,最后把A对象安装到B对象中去。

五、要点

          加载一个类到JVM中,由第一次调用这个类的静态成员触发。构造函数其实是一种特殊的静态函数。

          每个子类对象都独立的拥有一个属于它自己的父类对象。

你看我都这么努力的分享知识给你了,鼓励一下又何妨O(∩_∩)O

你的打赏是对我最好的支持!

                    

  • 13
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
### 回答1: UML对象图是UML中的一种图形表示方法,用于描述系统中的对象及其之间的关系,包括对象的属性和方法等。在进行编程时,我们可以根据对象图将系统的各个对象的属性和方法进行代码实现。下面是UML对象图转化为代码的步骤: 1. 分析对象图,确定对象的属性和方法。通过对对象图进行分析,我们可以确定各个对象的属性和方法。属性一般对应于类的成员变量,方法对应于类的成员函数。在确定属性和方法时,需要考虑对象之间的关系,如聚合、组合、继承等。 2. 根据属性和方法进行代码实现。通过定义类及其成员变量和成员函数进行代码实现。对于普通对象,我们可以直接定义类及其成员变量和成员函数。而对于组合、聚合、继承等关系,我们需要在定义类的同时考虑这些关系,并进行相应的代码实现。 3. 进行系统设计和编写。根据对象图转化为代码后,我们需要继续进行系统设计和编写。系统设计包括系统架构设计、模块划分、接口设计等,编写过程中要考虑系统的性能、可靠性、安全性等问题。 总之,UML对象图转化为代码是一项重要的工作,需要开发人员具备深入的UML理论知识及代码实现能力。只有将UML对象图转化为优秀的代码,才能为系统开发及维护工作提供方便和保障。 ### 回答2: UML(Unified Modeling Language,统一建模语言对象图是一种描述对象和它们之间关系的图形化表示方法。在软件开发中,对象图通常用于自顶向下的设计,即在设计系统结构时,首先绘制对象图,然后将其转化为源代码。下面我们来介绍一下如何将UML对象图转化为代码。 1.识别对象和类 首先需要识别出UML对象图中的对象和它们所属的类。对象通常表示为矩形,类通常表示为矩形上方有名称的矩形。在对象图中,对象通常与类形成实例化关系,即找到对应的类,实例化出一个对象。 2.识别对象之间的关系 在对象图中,不同对象之间会有各种不同的关系,如继承、关联、聚合、组合等。需要进一步识别对象之间的关系,并将这些关系转化为代码中相应的关系。例如,如果两个类之间存在继承关系,则需要在代码中实现继承。 3.编写代码 根据UML对象图中的对象和关系,编写相应的代码。在编写代码时,需要根据设计模式和编程规范进行,不同的项目会有不同的编程要求,需要遵守项目的编码标准。 4.测试 编写完代码后,需要对代码进行测试,确保代码能够正常运行,并且符合需求规格说明书和设计文档。 总的来说,将UML对象图转化为代码需要识别对象和类、识别对象之间关系、编写代码以及进行测试。这需要具备一定的编程能力和软件开发经验。了解面向对象编程思想,熟悉UML建模规范以及代码编写规范,可以更好地将UML对象图转化为代码。 ### 回答3: UML对象图是一种用于展示系统中对象及其关系的工具,其中包含对象、属性和方法,以及它们之间的关系。在开发过程中,我们可以利用UML对象图来更清晰地理解需求及设计,但它仍然只是一份图纸,需要将图纸中的内容转化为实际可执行的代码。本文将介绍如何将UML对象图转化为代码。 第一步:根据类图确定类 在UML对象图中,每一个对象都是一个类的实例,所以要将UML对象图转化为代码,首先需要确定每个类的定义。可以参考类图、系统规格说明书或需求文档来确定各个类的方法和属性。 第二步:定义属性和方法 在UML对象图中,每个对象都有一些属性和方法。因此,要将UML对象图转化为代码,需要先定义类的属性和方法,并为其赋予数据类型和可见性等属性。 第三步:定义类之间的关系 在UML对象图中,对象之间的关系可以通过不同箭头和线来表示。例如,聚合关系、组合关系、关联关系等。在代码实现中,也需要考虑这些关系,并确定如何表示它们。 第四步:定义构造函数 在UML对象图中,每个对象都需要根据其定义的类进行初始化。因此,在代码中也需要定义相应的构造函数来创建对象。 第五步:编写代码 在完成以上步骤后,我们可以开始将UML对象图转化为实际的代码。根据类定义、属性、方法和关系来编写代码,将UML对象图转换为可执行的代码实现。 总结 通过以上步骤,我们可以将UML对象图转化为实际的代码进行实现,并确保代码可以准确地反映出UML对象图中的对象、属性和关系等。这样做可以更好地理解需求及设计,并且能够提高代码的可维护性和可扩展性,使开发工作变得更加高效和可靠。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小大宇

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值