#V2EX

2d0154e14033e848...

npub195q4fc2qx05y3dzg49cny2lm7nsy52wrwuqjac844dnqnx6k7xks3pwpxu

hex

976ad7351cf8ddf450b33e0f7f1ce03deea226c5077c90d881396e671a7e6e9d

nevent

nevent1qqsfw6khx5w03h052zenurmlrnsrmm4zymzswlysmzqnjmn8rflxa8gprpmhxue69uhhyetvv9ujuem4d36kwatvw5hx6mm9qgsz6q25u9qr86zgk3y2jufj90alfcz298phwqfwur66kesfndt0rtg3x5039

Kind-1 (TextNote)

2026-03-18T11:48:46Z

#V2EX

[Java] 下面这段 Java 多态的代码,如何才能改为 Go、 Python 、JS、C++版本?

面向对象包括封装、继承、组合、多态,其中最不好理解,也最强悍的就是多态。可以说掌握了多态就掌握了面向对象以及设计模式的精髓。

但是 java 里面的多态实现太过于严苛,以致于其他语言都无法完全模拟。请看下面的代码,用其他语言实现的时候总难以达到类似效果。

/*
多态:即同一个行为具有多个不同表现形式或形态的能力。
表现形式为,子类重写父类方法,实现类实现接口方法,子类重写抽象类方法等。
多态三个必要条件:继承、重写、父类引用指向子类对象。多态有效消除类型之间的耦合,并提供灵活的可扩展方案。
本例子简单清晰明了的 Java 多态,能看懂这个例子就懂了什么是多态。
*/

// 父类 A
class A {
    public String show(D object) {
        return ("A and D");
    }

    public String show(A object) {
        return ("A and A");
    }

    // 默认注释掉。可开关注释测试下
    // public String show(B object) {
    // return ("A and B");
    // }
}

// 子类 B
class B extends A {
    public String show(B object) {
        return ("B and B");
    }

    public String show(A object) {
        return ("B and A");
    }
}

// 孙子类 C
class C extends B {
}

// 孙子类 D
class D extends B {
}

// 测试验证
public class PolymorphismSimple {
    public static void main(String[] args) {
        // 父类声明自己
        A a = new A();
        // 父类声明子类
        A ab = new B();
        // 子类声明自己
        B b = new B();
        C c = new C();
        D d = new D();

        // 1) A and A 。b 的类型是 B ,也是 B 的实例,A 里没有 show(B)方法,但有 show(A)方法。B 的父类是 A ,因此定位到 A.show(A)。
        System.out.println("1) " + a.show(b));

        // 2) A and A 。c 的类型是 C ,也是 C 的实例,C 继承 B ,B 继承 A 。A 里没有 show(C)方法,也没有 show(B)方法,最后指向 A.show(A)。
        System.out.println("2) " + a.show(c));

        // 3) A and D, d 的类型是 D ,也是 D 的实例,D 继承 B ,B 继承 A 。A 里有 show(D)方法,直接定位到 A.show(D)。
        System.out.println("3) " + a.show(d));

        // 4) B and A, ab 是 B 的实例,但用 A 声明,即向上转型得到的类型是 A ,运行时才能确定具体该调用哪个方法。
        // ab 是 B 的实例对象,但引用类型是 A 。类型是在编译时确定,因此从类型开始定位方法。
        // A 类中没有 show(B)方法,但有 show(A)方法,因为 A 是 B 的父类,ab 也是 A 的实例,于是定位到 A.show(A)方法。
        // 由于 B 是 A 的子类,且 B 重写了 A 的 show(A),A 的方法被覆盖了,于是定位到 B.show(A),这就是动态绑定。
        // 虽然 B 中有 show(B)方法,但是因为 ab 的类型是 A ,编译时根据类型定位到 A 的方法,而不是 B 。

        // 以下几种可开关打开/注释代码测试下。
        // -
        // 若 A 里有 show(A)和 show(B),B 里有 show(B)有 show(A),则编译时关联到 A.show(B),因 B 覆盖了 A.show(B),动态绑定到 B.show(B)。
        // -
        // 若 A 里有 show(A)和 show(B),B 里无 show(B)有 show(A),则编译时关联到 A.show(B),因 B 无覆盖,则直接调用 A.show(B)。
        // -
        // 若 A 里有 show(A)无 show(B),B 里无 show(B)有 show(A),则编译时关联到 A.show(A),因 B 覆盖了 A.show(A),动态绑定到 B.show(A)。
        // -
        // 若 A 里有 show(A)无 show(B),B 里无 show(A)有 show(B),则编译时关联到 A.show(A),因 B 无覆盖,则直接调用 A.show(A)。
        // 查找顺序为:编译时根据引用类型确定所属类 -> 根据重载参数类型定位(类型按子->父->祖逐级往上查找)到类的具体方法(包括继承的方法) ->
        // 运行时实例对象覆盖(覆盖只有子->父一层)了引用类型的同名方法 -> 定位到实例对象的方法。
        System.out.println("4) " + ab.show(b));

        // 5) B and A 。ab 是 B 的实例,类型是 A 。从 A 类没找到 show(C)方法,也没找到 A.show(B)方法,找到 A.show(A)方法。A.show(A)被 B.show(A)覆盖,因此调用 B.show(A)。
        System.out.println("5) " + ab.show(c));

        // 6) A and D 。A 里面有 show(D)的方法,直接定位到。
        System.out.println("6) " + ab.show(d));

        // 7) B and B 。B 里面有 show(B)的方法,直接定位到。
        System.out.println("7) " + b.show(b));

        // 8) B and B 。B 没有 show(c)方法,但有 show(B)方法。C 继承自 B ,父类型是 B ,因此调用 B.show(B)。
        System.out.println("8) " + b.show(c));

        // 9) A and D 。B 中没有 show(D)方法,B 继承 A ,A 里有 show(D), 故调用 A.show(D)方法。
        System.out.println("9) " + b.show(d));

        // 10) B and A 。父类声明子类,存在向上转型。A 里有 show(A),被 B.show(A)覆盖了,因此定位到 B.show(A)。
        System.out.println("10) " + ab.show(a));

    }
}

/**
 * 测试结果
 * 1) A and A
 * 2) A and A
 * 3) A and D
 * 4) B and A
 * 5) B and A
 * 6) A and D
 * 7) B and B
 * 8) B and B
 * 9) A and D
 * 10) B and A
 */

其他语言模拟实现: https://github.com/microwind/design-patterns/tree/main/programming-paradigm/object-oriented-programming/polymorphism https://www.v2ex.com/t/1199318#reply2

原始 JSON

{
  "kind": 1,
  "id": "976ad7351cf8ddf450b33e0f7f1ce03deea226c5077c90d881396e671a7e6e9d",
  "pubkey": "2d0154e14033e848b448a971322bfbf4e04a29c377012ee0f5ab66099b56f1ad",
  "created_at": 1773834526,
  "tags": [
    [
      "t",
      "v2ex"
    ]
  ],
  "content": "#V2EX\n### [Java] 下面这段 Java 多态的代码,如何才能改为 Go、 Python 、JS、C++版本?\n\n面向对象包括封装、继承、组合、多态,其中最不好理解,也最强悍的就是多态。可以说掌握了多态就掌握了面向对象以及设计模式的精髓。\n\n但是 java 里面的多态实现太过于严苛,以致于其他语言都无法完全模拟。请看下面的代码,用其他语言实现的时候总难以达到类似效果。\n\n```\n/*\n多态:即同一个行为具有多个不同表现形式或形态的能力。\n表现形式为,子类重写父类方法,实现类实现接口方法,子类重写抽象类方法等。\n多态三个必要条件:继承、重写、父类引用指向子类对象。多态有效消除类型之间的耦合,并提供灵活的可扩展方案。\n本例子简单清晰明了的 Java 多态,能看懂这个例子就懂了什么是多态。\n*/\n\n// 父类 A\nclass A {\n    public String show(D object) {\n        return (\"A and D\");\n    }\n\n    public String show(A object) {\n        return (\"A and A\");\n    }\n\n    // 默认注释掉。可开关注释测试下\n    // public String show(B object) {\n    // return (\"A and B\");\n    // }\n}\n\n// 子类 B\nclass B extends A {\n    public String show(B object) {\n        return (\"B and B\");\n    }\n\n    public String show(A object) {\n        return (\"B and A\");\n    }\n}\n\n// 孙子类 C\nclass C extends B {\n}\n\n// 孙子类 D\nclass D extends B {\n}\n\n// 测试验证\npublic class PolymorphismSimple {\n    public static void main(String[] args) {\n        // 父类声明自己\n        A a = new A();\n        // 父类声明子类\n        A ab = new B();\n        // 子类声明自己\n        B b = new B();\n        C c = new C();\n        D d = new D();\n\n        // 1) A and A 。b 的类型是 B ,也是 B 的实例,A 里没有 show(B)方法,但有 show(A)方法。B 的父类是 A ,因此定位到 A.show(A)。\n        System.out.println(\"1) \" + a.show(b));\n\n        // 2) A and A 。c 的类型是 C ,也是 C 的实例,C 继承 B ,B 继承 A 。A 里没有 show(C)方法,也没有 show(B)方法,最后指向 A.show(A)。\n        System.out.println(\"2) \" + a.show(c));\n\n        // 3) A and D, d 的类型是 D ,也是 D 的实例,D 继承 B ,B 继承 A 。A 里有 show(D)方法,直接定位到 A.show(D)。\n        System.out.println(\"3) \" + a.show(d));\n\n        // 4) B and A, ab 是 B 的实例,但用 A 声明,即向上转型得到的类型是 A ,运行时才能确定具体该调用哪个方法。\n        // ab 是 B 的实例对象,但引用类型是 A 。类型是在编译时确定,因此从类型开始定位方法。\n        // A 类中没有 show(B)方法,但有 show(A)方法,因为 A 是 B 的父类,ab 也是 A 的实例,于是定位到 A.show(A)方法。\n        // 由于 B 是 A 的子类,且 B 重写了 A 的 show(A),A 的方法被覆盖了,于是定位到 B.show(A),这就是动态绑定。\n        // 虽然 B 中有 show(B)方法,但是因为 ab 的类型是 A ,编译时根据类型定位到 A 的方法,而不是 B 。\n\n        // 以下几种可开关打开/注释代码测试下。\n        // -\n        // 若 A 里有 show(A)和 show(B),B 里有 show(B)有 show(A),则编译时关联到 A.show(B),因 B 覆盖了 A.show(B),动态绑定到 B.show(B)。\n        // -\n        // 若 A 里有 show(A)和 show(B),B 里无 show(B)有 show(A),则编译时关联到 A.show(B),因 B 无覆盖,则直接调用 A.show(B)。\n        // -\n        // 若 A 里有 show(A)无 show(B),B 里无 show(B)有 show(A),则编译时关联到 A.show(A),因 B 覆盖了 A.show(A),动态绑定到 B.show(A)。\n        // -\n        // 若 A 里有 show(A)无 show(B),B 里无 show(A)有 show(B),则编译时关联到 A.show(A),因 B 无覆盖,则直接调用 A.show(A)。\n        // 查找顺序为:编译时根据引用类型确定所属类 -\u003e 根据重载参数类型定位(类型按子-\u003e父-\u003e祖逐级往上查找)到类的具体方法(包括继承的方法) -\u003e\n        // 运行时实例对象覆盖(覆盖只有子-\u003e父一层)了引用类型的同名方法 -\u003e 定位到实例对象的方法。\n        System.out.println(\"4) \" + ab.show(b));\n\n        // 5) B and A 。ab 是 B 的实例,类型是 A 。从 A 类没找到 show(C)方法,也没找到 A.show(B)方法,找到 A.show(A)方法。A.show(A)被 B.show(A)覆盖,因此调用 B.show(A)。\n        System.out.println(\"5) \" + ab.show(c));\n\n        // 6) A and D 。A 里面有 show(D)的方法,直接定位到。\n        System.out.println(\"6) \" + ab.show(d));\n\n        // 7) B and B 。B 里面有 show(B)的方法,直接定位到。\n        System.out.println(\"7) \" + b.show(b));\n\n        // 8) B and B 。B 没有 show(c)方法,但有 show(B)方法。C 继承自 B ,父类型是 B ,因此调用 B.show(B)。\n        System.out.println(\"8) \" + b.show(c));\n\n        // 9) A and D 。B 中没有 show(D)方法,B 继承 A ,A 里有 show(D), 故调用 A.show(D)方法。\n        System.out.println(\"9) \" + b.show(d));\n\n        // 10) B and A 。父类声明子类,存在向上转型。A 里有 show(A),被 B.show(A)覆盖了,因此定位到 B.show(A)。\n        System.out.println(\"10) \" + ab.show(a));\n\n    }\n}\n\n/**\n * 测试结果\n * 1) A and A\n * 2) A and A\n * 3) A and D\n * 4) B and A\n * 5) B and A\n * 6) A and D\n * 7) B and B\n * 8) B and B\n * 9) A and D\n * 10) B and A\n */\n```\n\n其他语言模拟实现: \u003chttps://github.com/microwind/design-patterns/tree/main/programming-paradigm/object-oriented-programming/polymorphism\u003e\nhttps://www.v2ex.com/t/1199318#reply2",
  "sig": "f33120409e82706da23aea0f7088a6d6fc29c428b69ab85bc09b7698af61ca2e7d120389ca1a2e561ea19dab4df3ad2b7ee210241a1376630cd4d634539b3694"
}