首页 新闻 会员 周边 捐助

Parent p = new GrandChild(); 和GrandChild p = new GrandChild(); /l 区别

0
[已解决问题] 解决于 2025-08-16 18:54

Parent p = new GrandChild(); 和GrandChild p = new GrandChild(); /l
区别,深度分析

_java_python的主页 _java_python | 小虾三级 | 园豆:984
提问于:2025-08-16 15:16
< >
分享
最佳答案
0

(假设类继承链:Parent → Child → GrandChild):


1. 编译期类型 vs 运行期类型

  • Parent p = new GrandChild();
    • 编译期类型Parent(编译器只认Parent的成员)
    • 运行期类型GrandChild(实际执行时按GrandChild行为工作)
  • GrandChild p = new GrandChild();
    • 编译期类型和运行期类型均为`GrandChild

Java 的“声明类型”是把一部分单元测试提前到了编译期,用“约束”换“安全”。
Parent p = new GrandChild(); 就是显式告诉编译器:“请把我当成 Parent 来检查,逼我只用 Parent 的契约”。
这里的“安全”指的是编译期就能拦截、永远不会拖到运行时才爆炸的一类错误。
具体说,就是 “你调用了不存在的方法/字段,或者把对象塞进了不兼容的容器”——这类错误在 Python 里往往要等到单元测试甚至线上流量跑起来才被发现,而 Java 的声明类型可以在按下 javac 回车时就直接拒绝。
Parent p = new Child(); // 实际是 Child
GrandChild g = (GrandChild)p; // 编译器允许语法,但运行期抛 ClassCastException
虽然这里仍可能在运行期失败,但强转语法本身就是显式风险声明;编译器会强制你必须写 (GrandChild),让你意识到“这一步可能炸”。
没有声明类型时,这种错误可能在 Python 里通过鸭子类型潜伏得更深。
. 先分清两个“我”是谁

  1. 变量 p(左边的“我”)
  2. 真正 new 出来的对象(右边的“我”,即 GrandChild 实例)


2. “把我当成 Parent 来检查”——编译器眼里只有左边的“我”
‘’’’
Parent p = new GrandChild();
‘’’’
• 编译器看到变量 p 的静态类型是 Parent。
• 从此以后,只要源码里出现 p.XXX,编译器只会去 Parent.class 里找 XXX。
◦ 找到 → 通过。
◦ 找不到 → 直接报编译错误,哪怕 GrandChild 里真有这个方法。
• 这就等于告诉编译器:
“别管右边实际是什么,你就当它是 Parent。”
“逼我只用 Parent 的契约”——对写代码的人施加约束
• 契约 = Parent 公开的所有 public/protected 方法 + 字段 + 约定俗成的语义。
• 因为你只能看到 Parent 里声明的成员:
◦ 你无法直接写 p.childOnlyMethod() —— 编译期就拦下。
◦ 你也无法直接访问 p.childField —— 同样拦下。
• 于是调用者被迫只依赖 Parent 的“最小承诺”,不会意外耦合到 GrandChild 的额外细节。
◦ 将来把 new GrandChild() 换成 new Child()、new AnotherChild(),只要它们都是 Parent 的子类,调用方代码一行都不用改

只要把“契约”拆成两层看就通了:

  1. 契约的“接口”——编译器只认静态类型
    变量 p 被当成 Parent,因此 你能点出来的名字 只能是 Parent 里声明的;
    调用者写不出 p.grandChildOnlyMethod(),这就叫“只用 Parent 的接口”。
  2. 契约的“实现”——运行期按实际对象做事
    一旦名字被确定合法(例如 p.foo()),真正执行哪段字节码由实际对象决定。
    如果 GrandChild 重写了 foo(),那就跑 GrandChild.foo()——这属于 多态,并不破坏契约,反而正是契约的一部分:
    “我保证有一个叫 foo() 的方法,但具体表现由子类说了算。”
    所以:
    • 编译期:只能看到 Parent.foo() 这个名字(接口)。
    • 运行期:实际执行 GrandChild.foo() 这个实现(行为)。
    两者合起来就是 Java 的 “基于契约的多态”:
    调用者只依赖“有这个方法”的约定,而不关心“方法内部怎么做”。
_java_python | 小虾三级 |园豆:984 | 2025-08-16 15:19
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册