V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
huzhikuizainali
V2EX  ›  Java

“继承” 怎么就变成了“根据一个对象的实现定义了另一个对象的实现”?

  •  
  •   huzhikuizainali · 2023-10-14 23:39:52 +08:00 via iPhone · 997 次点击
    这是一个创建于 440 天前的主题,其中的信息可能已经有所发展或是发生改变。

    理解类继承和接口继承(或子类型化)之间的差别也十分重要。类继承根据一个对象的实现定义了另一个对象的实现。简而言之,它是代码和表示的共享机制。然而,接口继承(或子类型化)描述了一个对象什么时候能被用来替代另一个对象------《设计模式》

    接口不就是特殊的抽象类么(相对于抽象类而言,接口只声明方法,不声明属性或字段)。一个具体类实现接口,不就是一个类继承“接口”后实现了接口中声明过的方法么,这件事怎么就变成了“一个对象什么时候能被用来替代另一个对象”?

    其次类类的继承怎么就变成了“根据一个对象的实现定义了另一个对象的实现”。继承这件事不就是子类“继承”了父类中的属性和方法和方法么,怎么就变成了“根据一个对象的实现定义了另一个对象的实现”?

    netabare
        1
    netabare  
       2023-10-14 23:53:12 +08:00   ❤️ 1
    光是看 op 的描述感觉都要长脑袋了。

    建议用比较清晰的专业术语来描述一下,比如子类型( subtyping ),虚函数的派发机制(比如 dynamic dispatch ),还有早期绑定和多态( polymorphism )。说不定就没有这些疑惑了。

    现在看到这种模糊不清似是而非的语句真是头大。
    codehz
        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. 将自身标记为父类的子类型
    huzhikuizainali
        3
    huzhikuizainali  
    OP
       2023-10-15 00:23:00 +08:00 via iPhone
    @codehz 谢谢回复。请教一下
    1 、“ S 是 T 的子类型,但不是 T 的派生类型”,————这个用代码怎么实现?我的面向对象知识主要来自于 Matlab ,顺带看了一下 C++和 C#。从没遇到这种情况。

    2 、“ 所以 java 的类继承是做了两件事
    1. 复制父类的实现
    2. 将自身标记为父类的子类型”

    —————因为接口不存在任何“方法”的实现,只有方法的声明。所以不存在“复制父类的实现”这件事。所以当一个类 A 实现了接口 B ,并不能说 A 继承了 B ,我这么理解对么?


    另外,无论是“类的继承”还是“接口继承”。这里面都没有对象什么事情啊。我完全可以不实例化任何一个对象就完成类的继承,或接口的实现。《设计模式》中为什么总说“对象”如何如何?我觉得这里完全没有对象什么事情啊!
    netabare
        4
    netabare  
       2023-10-15 02:52:59 +08:00   ❤️ 1
    @huzhikuizainali 如果是 Java 语境里的「继承」关系,一个接口不能被具体实例化,接口和具体类之间的关系当然不是继承关系而是典型的子类型关系。codehz 的回复应该很清楚了。所以您应该知道前面问题怎么用代码来写了。

    而您的直觉也是正确的。

    我重新想了一下,或许这里讨论的是那种典型的 class extends 关系的,也就是父类先调用构造器后子类再调用构造器,然后逐个字段填入属性的这套过程。如果只从 Java 的角度很狭义地考虑的话,那么这个过程里面确实和对象有一点关系——调用构造器后会创建一个对象。或许,他想介绍一个子类对象可以被强转为父类的对象。这是我能想到的所有东西了。

    但是这个提法显然是有问题而且很含糊不清的。子类型或者继承/派生关系也确实不需要牵扯进来具体的对象的概念。说实话,关于类继承和接口继承,我觉得那两句话里面的对象换成类型,也就「类继承根据一个类型的实现定义了另一个类型的实现」,「接口继承描述了一个类型什么时候能被用来替代另一个类型」,反而更准确一些。不知道是书本翻译的问题还是原书对一些概念的解释不清楚。

    Java 的 OOP 和 C#的 OOP 没有本质上的区别,可能和 C++的有点区别就是。
    Al0rid4l
        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# 还稍好点...
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1191 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 18:11 · PVG 02:11 · LAX 10:11 · JFK 13:11
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.