00:01
大家好,我是海波老师,接下来我们继续来讲Java语法中的继承,我们这里来拷贝,拷贝以后呢,把这个一呢我改成二,点击OK,那么这里呢一呢改成二,好把里面东西都去掉。去掉以后呢,把下面这些啊,咱们也都给它删掉。这里我们就准备给大家讲一讲构造方法的问题。哎,老师呀,你是不是记错了,咱们构造方法咱们之前不是已经讲过了吗?咱们这里呢,又准备要再讲一遍呢?好,既然讲过了,我就问你一个问题,如果我们创建一个子类对象的话,父类对象会不会创建呢?你想一想。我相信这个问题啊,很容易就会想到父类对象肯定会被创建,对不对?没有负类对象,哪来子类对象呢,对不对?所以啊,咱们继续,我现在写上一个我们的class,我写上叫parent,我写上一个二,然后呢,放过来,我再来写上一个class,我们叫做CHILD2,然后呢,我放过来,我们让child呢来继承我的PARENT2就可以了。好了,我写完了以后,那么现在呢,我们就准备去构建我的CHILD2,然后呢,来C1,等于new我的CHILD2,这是我的第一个对象,然后呢,我再来一个,我写上一个C2,然后呢,我再来一个,我写上我们的C3。同学们,我们说过了,如果子类对象你创建我的父类对象,这个没有任何的问题,对不对?在生活中你得先有父亲,再有儿子,对不对?那我们这里呢,先有一个父类对象,再有个子类对象,我觉得这个应该是没有问题的。
01:26
可是啊,同学们,咱们想一个问题,咱们在当前当中啊,我们在这里有三个我的子类对象,对不对?我问同学们,我们这里呀,它有几个父类对象呢?大家想一想,我创建了几个PARENT2这个对象。我相信这里呢,大家就会有分歧了,为什么呢?我相信有的同学会说啊,老师你看我们的子类叫CHILD2,我构建了三个子类对象,但是呢,我们是继承了同一个父类啊,所以我们的父类对象不就创建一个吗?这就好比我们一个父亲有多个孩子的感觉,不就这意思吗?但有的同学说,老师你看我们这里呢,三个new,我构建了三个子类对象,那我们的负类对象不就构建了三个吗?所以啊,我相信不同的同学可能就有不同的想法,对吧?那么我们这里到底应该有多少个呢?所以我们就得验证一下了,那怎么验证呢?很简单,咱们前面讲过了,咱们构建对象的时候,它的构造方法它就会执行啊。
02:18
所以我们这里写上我的CHILD2好了,写完了以后写个括号,然后呢写个它,这就是我们CHILD2它的一个构造方法,所以呢,我们这里写上它,诶放过来,我放过来以后,那么这时候需要注意的同学们,我写上它就叫跳点点点点点点之后呢,我现在运行一下,你会发现我们当前的子类对象,它会执行我们的三次,为什么呢?因为咱们构建了三个子类对象,对不对?但是问题在于我们的父类到底构建了多少个呢?其实啊,负类也有构造方法呀,所以我写上它,咱们这里叫PARENT2,然后呢,写上一个括号,然后再写上一个它,那么这个时候呢,我们给它写上它拷贝,拷贝以后呢,同学们,我写上叫parent,你这么写不就可以了吗?好了,那我们准备去执行一下,好了,同学们,那么我们现在呢,运行一下,看结果,运行以后你会发现我们的parent它确实执行了一次,两次,三次,也就意味着我们的负类对象其实也创建了三个。
03:18
这个大家能不能看到应该没问题吧,因为咱们通过执行的已经看到了结果,对不对,那么也就意味着呀,我们的负类对象确实创建三个,但是同学们你要注意,我们看看,我们再来执行一下,看看它的执行顺序,我们这里是这样的,我先执行parent,然后呢再去执行child,然后呢,我再进行parent,我再进行child,我再进行parent,再进行child,这就说明啊,我们的父类对象,它就是在我构建子类的对象的时候创建出来的,所以我们这里说一下。我们的父类对象,它是在我们子类对象创建前创建完成的,也就意味着我要创建一个子类对象,它会首先先把父类对象创建好,所以我说一下创建子类对象前啊,那么会调用。
04:08
父类的构造方法,完成负类的创建。诶,我相信这个大家是能够理解的,但是之前同学们为什么会认为是一个呢?其实恰恰呢,是跟我这个图有关系,我们之前给大家画图的时候说了啊,我们的子类一,子类二,子类三,继承了同一个父类,对不对?所以啊,我们这么说的话,同学们可能就误会了啊,我们的三个子类对象有一个父类对象,其实啊,我们之前讲的是没有错误的,但是我们说的是类型之间的关系,也就意味着我们说的不是对象的创建,我们说的是类型的关系。这就好比什么呢?这就好比我们今天给大家讲基本数据类型一样,我们说了基本数据类型当中有什么整形啊,浮点类型啊,什么布尔类型啊,诶说的是他们的关系啊,同学们,我们这儿也是一样的,从关系的角度来讲,一个子类它只能继承一个父类,而一个父类呢,会有多个子类来继承,所以说的是这种关系。但是如果从对象的角度来讲的话,不同的子类都继承了同一个父类,并不意味着他们的父类是同一个对象。
05:12
因为父类的构造方法会被调用三次,这就意味着其实创建了三个父类对象,这就好比生活中我们都有自己的父亲,但是巧了,他们的名字相同,都叫张三,就是这个感觉,它就是名一样,但不是一个人。所以真正体会父子类应该是怎样体会呢?我们把图改一改,就意味着我们从对象的角度,我们不这么画了,把它复制一下,复制以后干嘛呢?放过来,记住啊,我们说一下,咱们叫做对象。你从对象的角度来讲的话,我们这里该怎么画呢?我把这个都去掉啊,都去掉,然后呢,把这个子类的我画的稍微大一些,把它画大一些,画大一些以后把这个呢,来我们写上子类一往下挪一挪啊挪一挪。挪完了以后,把这个副类呢,给它放到这里去。你放到这里去,然后干嘛呢?把它我复制一份,复制以后放过来,放过来以后我写上它,咱们叫做什么呢?叫做子类二,这是我的第二个子类,那我这里呢,其实应该写上叫负类一,负类对象一,然后呢,写上它,我们叫负类对象二,然后呢,我再复制一下,同学们能不能明白老师说的意思,我这么写其实才是对的啊,我们称之为叫负类对象三呢,行了,那我箭头呢,我就指向一下什么意思,我们的三个负类对象,记住它们的名字都是一样的,所以我们复制过来,把这个呢复制过来吧,复制过来以后我们这里给他一个方块放过来啊,来说一下它的名字叫parent,同学们这个大家能不能明白,我们的名字叫parent,但是对象呢,是在我们子类当中的,我们不说过了吗?我们父类对象的东西,我们子类什么都不用做,不就全都有了吗?那好,从内存的角度来讲,我包含了你,不就意味着你的东西我全有了吗?所以啊,咱们这么画其实应该是准确的,同学们,所以记住了啊,从对象的角度。
06:56
来讲的话,他们的对象有三个,只是名字都叫parent,但是呢,从类型的角度来讲的话,我们的不同的子类他们确实是有相同的副类,所以角度不一样,这个呢需要给大家说明一下,那么同学们现在能不能明白了呢?好,我们再说另外一个问题,如果负类的构造方法它如果有参数了怎么办?同学们比方说我的PARENT2这里呢,我需要传一个参数,咱们前面不讲过了吗?构造方法它也是方法呀,它是可以传参数的,而我们的构造方法要传参数的目的不就是为了给我们的属性赋值吗?所以呢,我们这里写上它叫string user name,好,写完了以后我把user nameme呢,A,把这写成它等于name就可以了。
07:40
那我写完以后,这个属性我们的子类就完全拥有了,对不对,诶老师你看报错了,他怎么报错了呢?是因为我们的CHILD2啊构建不出来了。为什么构建不出来了?很简单,因为它不知道怎么来创建我的父类对象,我先不说了嘛,你要想构建对象的话,首先得先把父类对象构建出来,你再构建我的子类对象,从图形的角度来讲的话,我得先构建这个红色的内存,对不对?我再把黄色的内存给我构建出来,可是啊,同学们,我们的红色的负类对象我都不知道怎么构建。
08:14
为什么不知道怎么构建,很简单,他传参数你没传呀,你没传你怎么做呢?诶老师那我咋传呀,很简单跟大家解释一下,咱们之前不是讲过一个叫super关键字吗?这里给大家说一下来。默认情况下。我们的子类对象构建时。它会默认调用负类的构造方法完成。负类对象的创建。使用的是super的方式。只不过啊,Java虚拟机自动完成,也就意味着你不用写了,哎,什么意思呀,大家看一下我们之前为什么没问题呢?是因为我们这里面有一个叫做super。这个super呢,你写个括号,大家还记得咱们之前讲过那个super关键字吧,这个关键字就表述的是我们的super来调用了上一级或者叫副类的这个构造方法,所以呢,我们之前是这个样子的,如果你想用这种方式完成负类对象的创建,你就不用写了,为什么呢?
09:15
因为Java虚拟机可以帮你完成这个操作,但是呢,现在就完成不了了,为什么?因为我们的父类啊,它已经有构造方法了,Java虚拟机就不会提供那个叫无参的构造方法,而你这个地方恰恰是没有参出的。哎,老师,那怎么办呀,很简单呀,你把这里传一个值写上一个张三,诶同学们有没有发现你这么写就行了,可以了,之后呢,我们现在运行一下来运行一下看结果,你会发现没有任何的问题,这就说明啊,我们在子类的构造方法中,我们其实应该去调用负类的构造方法,但是如果它是默认的无参的构造方法,你就可以省略,如果它有参数,你就必须要去显示的调用,所以咱们这里也写上它来。如果负类,它提供了构造方法。
10:04
那么我们Java虚拟机,它不会提供默认的构造方法。那么我们的子类应该显示调用我们的super方法来构建父类对象。所以啊,这就是我们给大家演示的啊,构造方法其实是有一些特殊的,好同学们继承当中的构造方法,咱们就讲到这里。你们是不是以为咱们的构造方法已经讲完了,视频该结束了呢?诶,其实啊,按照套路上来讲的话,确实是这样的,讲完构造方法的应用之后啊,咱们的视频就应该停下来了,但是还不行,为什么呢?因为我们前面的讲法呀,是为了让同学们能够对构造方法有一个直观的认识和理解,更容易上手,所以讲解过程中啊,有些地方其实是做了相应的改动的,也就是说和实际的语法原理啊是有一些偏差的,那么接下来我们就要对其中的一些细节做一些修正和补充。首先我们第一个要说的就是我们的new这个关键字,咱们这个new关键字啊,咱们前面讲过了,一个new就会构建一个对象,这个是没有问题的,所以咱们说一下,咱们叫构建一个对象,但是同学们记住了,我们的new,它只会构建一个对象。
11:16
你构建对象没问题,但是你只会构建一个对象,你不能说我写上一个new,诶,我构建两个对象没有这个能力啊,也就是说在内存中只会开辟一块内存空间来存储这个创建出来的对象,所以啊,咱们前面提到构建子类对象的时候啊,负类对象也会被构建出来,这句话是不准确的,为什么?因为负类对象如果也可以构建出来的话,那不就是两个对象了吗?那么和这个new的语法不就有冲突了吗?所以啊,这里其实我们并没有把负类的对象构建出来,这是我们第一个要说明的,第二个要说明的就是咱们前面画的这个图形啊,也不是很准确,其实啊,我们画的这个图啊,本质上没有任何的问题,那么这里的黄色的圆圈呢,它表述的就是一个对象,但是这里的红色的圆圈呢,表述的就不是一个负类对象了,因为根本就没有负类对象,咱们刚刚提过对不对?这里呢,是为了存储从父类继承过来的成员属性和成员方法而专门开辟的一块内存空间。
12:16
所以呢,将这个红色的圆圈画到黄色圆圈的里面是没有任何问题的,因为它继承过来了嘛,所以我的里面是有它,只不过它来自于我的父类,所以这个是没有任何问题的啊,这个咱们给大家去说一下,但是呢,我们叫副类对象可能就不够准确了,而且呢,我们这个红色圆圈当中的那些副类属性数据的初始化操作,就是由咱们负类的构造方法完成的。诶,提到了构造方法,那咱们接着就是说构造方法的问题,咱们前面讲过了,子类的构造方法执行之前,它必须完成负类构造方法的执行,这个说法是准确的,但是你要注意,咱们这里的构造方法呢,也叫constructor,叫构建器,从名称上来讲啊,容易让你误会了啊,你会认为呢,调用完了这个构造方法之后,对象才会创建出来,这不叫构建器嘛,对吧?把对象构建出来不是这样的,其实啊,是我们的对象构建完成了之后,在内存中开辟了我们的内存空间以后,才会执行我们所谓的构造方法,所以啊,它的先后顺序你要明确了,先有对象开辟了内存空间,再执行这个方法,所以构造方法的主要目的就是为了完成我们内存空间属性的初始化操作,所以我们从父类继承过来的这些属性,他一定要提前给他初始化,这也是我们为什么之前我们的子类的构造方法必须要去调用我们父类构造方法的原因。
13:41
对不对,你必须要给负类的属性初始化,这个希望大家能够明白,所以啊,我们把这些东西呢,给大家稍微的补充一下,因为咱们前面的地方呢,是为了让大家好理解,所以啊咱们讲的跟现在有一些不同,但是我希望大家能够明白,我们画图的时候,我们教父类,但是它不是真正的有个对象存在,这个咱们需要明确了啊,好了,这回我们视频呢就真的就结束了啊。
我来说两句