#V2EX

2d0154e14033e848...
npub195q4fc2qx05y3dzg49cny2lm7nsy52wrwuqjac844dnqnx6k7xks3pwpxu
hex
976ad7351cf8ddf450b33e0f7f1ce03deea226c5077c90d881396e671a7e6e9dnevent
nevent1qqsfw6khx5w03h052zenurmlrnsrmm4zymzswlysmzqnjmn8rflxa8gprpmhxue69uhhyetvv9ujuem4d36kwatvw5hx6mm9qgsz6q25u9qr86zgk3y2jufj90alfcz298phwqfwur66kesfndt0rtg3x5039Kind-1 (TextNote)
#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
Raw 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"
}