[音乐] 例 21 继承,在这样的一个例子里 面,我们初步地接触一下继承。 那么在这个例子里面 我们着重看一下继承里面的这样的一个构造函数的这样的一个使用 以及理解一下继承。 那么我们要做一个什么样的例子呢?我们要 首先要创建一个点类,这个点类表示平面上的一个坐标的一个坐标 那么有一个 x 和有一个这样这样的一个 y 的值 随后我们从这个点类里面继承,继承。 然后那么继承出来一个圆 圆类,添加一个新的这样一个字段,那么就是它的这个圆的半径 那么然后随后我们来计算这样一个圆的面积 好了,现在我们来看一下这个题 这是我们的第 21 个例题 [无声] [无声] [无声] [无声] 选择 cause [无声] [无声] 同样的我们把这个例子拷过来 [无声] [无声] [无声] [无声] 好了 首先我们来创建这个点的这个类,这个我们应该比较熟悉了 class Point 我们创建了这样的一个 Point 那么在这个 class Point 里面,我们把这个 class 写到这,class Point 在这样的 class Point 里面,那么注意一下,如果你这个 Point 希望被 其他的程序集所引用的话 这就需要在前面添上这个 public ,不要忘了。 如果只是在这样的一个名字空间或者这样的一个 这样的一个 DIL 程序集里面,就是只在这一个例 21 里面使用 Point 的话,那么你可以把它 去掉,它默认是 private。 那最后我们要 两个点,那么这两个点呢作为它的圆心,可能将会被它的这样的一个 子类所继承。 那么要让它的子类所继承的话,那么就要把 这样的一个点的这样的一个属性访问权限生为成 protected protected 的属性意思是可以在 继承的子类跟父类之间,它们可以继承可以使用这样的一个变量 可以访问这样的一个字段。 但是 从外部是不能够访问的,那么如果你把它生成 private 的话 那么它的这样的一个子类就没有办法读取这样的一个 父类的 private 的字段,那么有可能我们在后面的圆里面还要改变自己的圆心,所以说我们需要继承这样的一个 字段 double。 那么这是它的这样的一个 x 坐标 protected double y 坐标 那么当然我们也可以把这样的一个字段 x y 直接设定为什么呢?设定为这样的一个 属性,设定为属性。 那么而不用这样的一个变量或者字段的形式表示 那么也是可以的。 那么如果你需要对这样的一个,因为我们通常 有了这样的 x, y 之后,那么我们可能还是需要对这样的一个 x, y 有这样的一些 存取或者一些这样的一个东西可以设定这样的一个圆的 圆心,然而具体到底要不要给 x, y 什么样的级别的权限?是 public 的呢? 还是可以直接存取呢?还是 protected 呢?还是这个 private 呢,可能跟你当时自己的一个类的 设计有关。 好了,我们先来 来看 public ,然后我们首先要提供一个这样的一个 Point 的构造函数 那么按着我们的这个习惯要求,我们可以把它提供为两个构造函数,一个怎么样呢? 一个是这样的一个设为 0 的这样的一个函数 public Point 它提供的这样一个构造函数应该是一个 int x1, int y1 那么在这样的一个构造函数里面,我们让 x 等于 x1 也就是说给定的两个初值来什么呢?来构造这样的一个 Point y 等于 y1 那么在这样一个里面,我们还提供一个 public 的构造函数叫做 显示一下这两个点的坐标,那么它是一个 void 的型的 在这个坐标里呢,我们简单地显示一下x 跟 y 的值 [无声] x 等于 0 那么 暂时,暂时我们显示了一些我们做了一个示例,那么构造了这样的一个 Point 类 这个在我们前面已经写了很多很多类了,不是重点 那么下面重点是什么呢?下面是如何从这样的 一个 Point 类进行继承?怎么样来写这样的一个继承? public class Circle,继承的写法是,继承的写法是 空格、 冒号,然后怎么样呢?后面跟上从哪一个类继承 Point 从 Point 类继承,那么这样 这样就是然后括号,这就是什么呢?这就是继承的写法 一个冒号后面跟这样的一个集类的名字。 冒号后面跟集类的名字,继承的写法 Point、 Point、 冒号、 Point。 那么一旦继承了的话 那么我们就有了这样的一个,就可以使用这样的一个 Point 里面的这样的一个 protected、 public 这样的一些函数和这样的一些iii了 当然了构造函数啊,构造函数是不能够被继承的,只能继承 这样的一个字段,还有这样的一个 public 数这样的一个函数都能够被继承 那么有了这样的一个继承了之后 那么我们再增加一个新的这样的一个 一个字段 r 表示这样的一个圆的这样的一个半径 同时怎么样呢?同时我们来增加,我们来写出自己的这样的一个 Circle 的构造函数。 对于这样的一个 Circle 这样的构造函数来讲 我们也提供一个不带参数的构造函数,那么直接让 r 等于 0 就可 其次,我们再提供一个完整的 构造函数,那么这个构造函数可以初始化一个圆心坐标 同时初始化一个半径的值。 特别要注意的是这个构造函数的写法 首先 public,然后构造函数 Circle 完了之后后面有一个所谓的参数总表 就是说我需要把所有初始化的参数,我自己的还有 包括我的父类的参数要全部写在这个参数总表里面 因为创建 Circle 的时候,虽然创建 Circle,要首先创建 Point 类 但是首先是由操作系统调用的 Circle 这个的一个构造函数来创建 Circle 的 而不是先调用了这样的一个 Point 的构造函数,顺序是由 操作系统先调用了Circle 的构造函数,而 Circle 的构造函数发现自己是从 Point 继承的 会马上再调用 Point 的函数来创建这样的一个对象 那么因此既然操作系统首先是调用的是 Circle 的构造函数,那么所有的 参数都是应该由这样的一个构造函数传进来的,因此它带有三个参数,分别是 分别是 x1, y1, r1,其中 x1, y1 是圆心坐标,是给什么呢?是给它的父类的 那么如何把 x1, y1 传递给父类呢?我们有一个语法,标准的语法写法就是 括号 base,第一个关键词是一个关键字来 蓝色的 base 表示把这个参数怎么样呢 x1 逗号,y1,这个参数的类型写错了,参数的类型应该是 double 三个都是 double,这个无关、 无关 无关紧要。 那么 把这样的一个参数传递给这样的一个父类,同时 r 等于 r1,这是自己用的,r 是在这里面申明的变量,所以说这个 r 等于 r1 特别要注意的是 嗯?无效的参数 这个框里头没有写对 这个框它也应该是 double 否则会引起参数iii,double 那么 注意这个 base 的写法,这个 base 的写法其实相当于 通知这个 circle 的构造函数,在创建 circle 之前要先调用 基类的构造函数。 所以说这其实是一个函数参数的传递跟调用,而不是一个申明 因此在 base 里面就直接是 x1 y1,有一些初学者曾犯的错误的是在这边增加了一个 int 这是不对的,或者一个double,或者一个double,把这样的一个申明写到这,这- 是不对的写法 千万不要这样写,这是一个函数的调用,直接那么呢就是函数的 x1 跟 y1 调用完了之后,写法是冒号、 base、 冒号、 base 那么调用完了之后,在这个函数期里面初始化自己的这样的一个 函数代码,那么这是一个标准的做法。 再来,我们来看一下 public public 我们计算一下面积,这是一个我们普通的增加的函数 这就跟前面我们所讲的类的这样的一个函数就 区别就不大了。 return Pi… 面积应该是Pi r 的平方,跟圆心坐标到没有什么关系 math dot Pi 乘以 r 再乘以 r 那么,我们再来看一下,如果我们要把 在这个,在这样的一个 里面我们也要显示一下这样的一个值,那么我们可以再写一个 void show,我们这个时候怎么样呢,我们这时不要把这个 show 和这个 show 写得暂时重名,show 跟 show 要两个函数需要重名的时候 我们需要,我们需要在下一个例题里面、 下两、 几个例子再进行详细的讨论 那么 写一个 show2,因为我们要显示这时候我们直接显示 两个点的坐标,再显示什么呢?再显示这样自己的半径 那么两个点的坐标,我们在、 在这样的我们的这个 父类里面已经有一个 show 函数,所以说我们直接调用这样的 show 函数 这就是一开始我不要求你们把它写成重名的一个原因,如果你在这边又写一个了 show 的话,在这里面再调用 show 的话 无疑会引起这样的一些相当的混淆 那么写完了这样的一个 show 函数之后,我们再 再输出,再输出这样的一个 r 的值 [无声] 那么,我们首先把这样的一个简单的 例子先写成这个样子,写成这个样子。 然后我们再来回顾一下这个例子 我们这个例子首先创建了一个 public class 的 point 在这个 point 里面我们有两个、 有两个 protected 类型的iii全新的字段或者变量,分别是 x 跟 y 然后有一个这样的一个不带参数的这样的一个构造函数 以及有这样的一个带有两个参数的构造函数 初始化了 x y 的值,已经有一个普通的 show 函数 显示了 x 跟 y 的值 这就是整个 class 里面的内容 那么在这个 class 这样的一个 circle 里面,从 class 继承,注意这是一个继承的写法 这是继承的写法,在这样的一个继承里面我们增加了 一个字段叫做 double,是作为这样的一个圆的半径 同时我们也提供了一个不带任何参数的这样的一个东西,把它初始化了 为 0 ,然后我们提供了一个三个参数的这样的一个构造函数 其中有两个参数是参数总表包含了它父类的参数和其他自己类的参数 随后冒号,通过关键字 base 把前两个参数传给父类 调用父类的对应的构造函数,那么 r 等于 r1,然后 这样作为它的这样的面积。 那么在这里面需要特别注意的 两个问题,在这个构造函数里面,第一这是一个参数总表 需要接收自己的参数和父类的参数,所有的参数都要在这个参数总表里面列出来 第二,通过 base 调用父类的构造函数,或者说传递给父类的构造函数 那么,特别注意的是在传递的时候,这个 base 里面这个函数参数的个数 参数的个数和参数的类型一定在父类里面要有一个 在父类里面要有一个对应的、 对应的同样参数个数跟参数类型的 构造函数才能够成功。 对吧,如果我这边的 base 只有一个 x1 只有一个 x1,没有后面的 y1 就完了,x1 括号就完了,那么就是一个 double 参数的构造函数 显然这里会报错。 为什么呢?因为在父类里面不具备有一个参数的 构造函数。 再 下来,我们增加一个普通的 函数。 在这个函数里面我们看到我们可以直接调用父类的函数 可以直接调用父类的函数,这就是继承。 这个 show 是我们从上面继承下来的,就好比我们已经有了这样的 一个 show 一样。 同样的,在我们所有的不管是在这个面积函数里面 在这个输出函数里面,如果需要的话,也可以直接使用 point 里面的 x 跟 y 这样的一个字段的值 给它赋值,或者给它取出来的值等等。 那么也就是我们也 继承了 x y show, 这样的东西都是我们继承下来的 OK,我们在主函数里面稍微 做这样的一个测试。 那么在主函数里面我们 我们是创建一个 circle 的变量,一个 c1 等于一个 new circle。 在这个 circle 里面我们并没有给出任何参数,我们调用下 c1 点 这时候看到我们不但是 show2 可以调用,show 也可以调用,只要是我们继承的 public 的 protected public 都可以调用,当然了 protected 你就没有办法直接从外部调用了 circle,我们再创建一个变量 c2 等于 new circle,那么它的圆心坐标我们设定为 (2, 3),半径设定为4 那么随后怎么样呢?随后我们 c2 点 show 2 同时我们也可以看见我们仍然也可以调用一下 c2,c2,c2 点 show [无声] 那么然后我们运行一下这个程序看一下 我们会看到 x 等于 0,y 等于 0 ,r 等于 0 怎么样呢,是我们第一个这样的一个 c1 的对仗的输入,x 等于 2,y 等于 3,r 等于 4 是第二个对仗的输出 那么调用、 再次调用 show 的时候,是x 等于2, y 等于 3 ,是它的坐标的输出,就没有 r 的输出了 那么,在这样两个不同的对象的创建过程中,我们看一下这样的一个线路图 对于这样的一个 c1 来讲,它首先调用的是一个没有参数的构造函数 所以对于 c1 来讲对应的这样的一个circle 首先会调用的是 首先会运行的是这个 public circle,会开始调用这个构造函数 那么在这个调用这个构造函数之前,circle 发现自己是从 point 怎么样进行继承的 那么由于后面并没有任何 point 的这样的一个 的参数的这样的一个调用,所以说怎么样呢 会首先再去找 point 里面有没有一个不带参数的构造函数,找到 那么因此在会调用这个 point 的构造函数,把 x y 初始化为 0 了之后 先创建 point 的对象,成功了之后,再来执行 circle 的这个构造函数 r 等于 0 创建完 circle 对象,那么整个对象就创建完了 那么就可以进行 c1 c2 c1 的调用了。 那么对于这样的一个 c2 这样的一个来讲 对于 c2 来讲,那么它首先有这样的一个三个参数的这样的一个构造函数 因此首先会在 circle 里面寻找是否具有 三个参数的构造函数,那么找到了这样的一个构造函数 在这样的一个构造函数里面会看到传递给了 base 有一个这样的构造函数 因此怎么样呢,会同时要查找 point 里面有没有两个这样的一个构造, 有! 查找到了,查到到了之后怎么样呢?查到到了之后首先会调用 point 的这个构造函数,用传递的 x1 y1 来初始化x y,就是 2 跟3 同时调用完了之后,那么把 r1 这个 4 传递给 r, 构造出来我们这样的一个对象 c2 好了,那么我们 问题,有一个问题我们给大家思考一下:如果我把这个 base 删去,那么这个程序能不能运行呢? 我们来试一下。 我们会看到 这个程序没有什么错误的提示,没有什么错误的提示,然后我们再一次按一下 Ctrl F5 运行一下。 我们看到这个程序仍然是可以运行的,但是 唯一的不同的是这时候 x 等于0,y 等于 0,r 等于 4,同时 x 等于 0,y 等于 0 也就是说什么呢,也就是说如果后面没有一个对主函数的一个 调用的话,那么就会默认的调用父类的一个不带参数的构造函数 不带参数的构造函数。 再下来,更进一步 的说如果我在 point 里面没有写这个构造函数的话 那么这时候就会出错,因为我们需要一个不带参数的构造函数,而 父类里面没有这样的一个构造函数 同时在这里面我们再强调一下那个默认的构造函数 如果你一个构造函数都没有的话,那么编辑会添加一个 会添加一个不带任何参数的默认的构造函数 但是一旦你写了一个自己的构造函数的话 编辑就不会再为你、 为你添加任何的构造函数 因此,如果 如果我把这个构造函数再给去掉的话,同时也把这个 base 去掉 首先这个 circle 就已经不对了,对吧,首先这个 circle 因为它也 依赖于要一个后面要带一个不带参数的构造函数 那么如果我把这个 base 再去掉的话,那么这块也会出错 这块也会出错,它也需要一个不带参数的构造函数 那么因此怎么样呢,因此,因此我们看到 当一个类要能够正确的构造的时候 当一个类要能够正确的构造的时候,那么 那么,主要的就是在 继承类跟父类之间有相应的构造函数 相应的构造函数,能够正确的按照这样的一个构造函数的 传递方式能够把这样的一个类、 对象构造出来 这是这次主要是关于我们对 继承和构造函数的讨论就到这