理解类继承和接口继承(或子类型化)之间的差别也十分重要。类继承根据一个对象的实现定义了另一个对象的实现。简而言之,它是代码和表示的共享机制。然而,接口继承(或子类型化)描述了一个对象什么时候能被用来替代另一个对象------《设计模式》
接口不就是特殊的抽象类么(相对于抽象类而言,接口只声明方法,不声明属性或字段)。一个具体类实现接口,不就是一个类继承“接口”后实现了接口中声明过的方法么,这件事怎么就变成了“一个对象什么时候能被用来替代另一个对象”?
其次类类的继承怎么就变成了“根据一个对象的实现定义了另一个对象的实现”。继承这件事不就是子类“继承”了父类中的属性和方法和方法么,怎么就变成了“根据一个对象的实现定义了另一个对象的实现”?
1
netabare 2023-10-14 23:53:12 +08:00 1
光是看 op 的描述感觉都要长脑袋了。
建议用比较清晰的专业术语来描述一下,比如子类型( subtyping ),虚函数的派发机制(比如 dynamic dispatch ),还有早期绑定和多态( polymorphism )。说不定就没有这些疑惑了。 现在看到这种模糊不清似是而非的语句真是头大。 |
2
codehz 2023-10-15 00:02:15 +08:00
主要是混淆了“继承/派生”和“子类型”的两个关系
它们原则上应该是正交的关系,不过在 java 里,类继承同时包含了学术意义上的“继承/派生”和“子类型”,实现接口(不考虑默认实现这个新玩意)则只包含“子类型关系” 也就是说,理论上类型 S 和类型 T 的关系有这 4 种可能性 1. S 既不是 T 的子类型也不是派生类型 2. S 是 T 的子类型,但不是 T 的派生类型 3. S 不是 T 的子类型,而是 T 的派生类型 4. S 既是 T 的子类型又是派生类型 而 java 禁止了 3 这个选项 子类型关系,可以简化为 is-a 关系,就是你所看到的“替代另一个对象”的描述 继承关系,才是复制/共享实现的含义,也就是“根据一个对象的实现定义了另一个对象的实现” 所以 java 的类继承是做了两件事 1. 复制父类的实现 2. 将自身标记为父类的子类型 |
3
huzhikuizainali OP @codehz 谢谢回复。请教一下
1 、“ S 是 T 的子类型,但不是 T 的派生类型”,————这个用代码怎么实现?我的面向对象知识主要来自于 Matlab ,顺带看了一下 C++和 C#。从没遇到这种情况。 2 、“ 所以 java 的类继承是做了两件事 1. 复制父类的实现 2. 将自身标记为父类的子类型” —————因为接口不存在任何“方法”的实现,只有方法的声明。所以不存在“复制父类的实现”这件事。所以当一个类 A 实现了接口 B ,并不能说 A 继承了 B ,我这么理解对么? 另外,无论是“类的继承”还是“接口继承”。这里面都没有对象什么事情啊。我完全可以不实例化任何一个对象就完成类的继承,或接口的实现。《设计模式》中为什么总说“对象”如何如何?我觉得这里完全没有对象什么事情啊! |
4
netabare 2023-10-15 02:52:59 +08:00 1
@huzhikuizainali 如果是 Java 语境里的「继承」关系,一个接口不能被具体实例化,接口和具体类之间的关系当然不是继承关系而是典型的子类型关系。codehz 的回复应该很清楚了。所以您应该知道前面问题怎么用代码来写了。
而您的直觉也是正确的。 我重新想了一下,或许这里讨论的是那种典型的 class extends 关系的,也就是父类先调用构造器后子类再调用构造器,然后逐个字段填入属性的这套过程。如果只从 Java 的角度很狭义地考虑的话,那么这个过程里面确实和对象有一点关系——调用构造器后会创建一个对象。或许,他想介绍一个子类对象可以被强转为父类的对象。这是我能想到的所有东西了。 但是这个提法显然是有问题而且很含糊不清的。子类型或者继承/派生关系也确实不需要牵扯进来具体的对象的概念。说实话,关于类继承和接口继承,我觉得那两句话里面的对象换成类型,也就「类继承根据一个类型的实现定义了另一个类型的实现」,「接口继承描述了一个类型什么时候能被用来替代另一个类型」,反而更准确一些。不知道是书本翻译的问题还是原书对一些概念的解释不清楚。 Java 的 OOP 和 C#的 OOP 没有本质上的区别,可能和 C++的有点区别就是。 |
5
Al0rid4l 2023-10-15 13:39:29 +08:00
@huzhikuizainali
"S 是 T 的子类型,但不是 T 的派生类型" JS/TS 的结构子类型 "一个对象什么时候能被用来替代另一个对象" 大概是想表达里氏替换...也许用"一个变量什么时候能被用来替代另一个变量" 会显得更加合适 "根据一个对象的实现定义了另一个对象的实现" 其实也可以参考 JS 原型链... 你说"一个类 A 实现了接口 B, 或者 A 继承了 B" 广义上来讲都没什么问题, 纠结这些字眼意思不大, 没事就继承都是那个年代推 OOP 给 C++/Java/C# 掺的屎, C++ 和 C# 还稍好点... |