为什么 Java 父类构造函数调用被重写的方法会调用到子类的

讨论 未结 30 39
movq
movq 会员 2022年11月17日 16:36 发表
<pre><code class="language-java"> public static void main(String[] args) { class Parent { Parent() { print(); } void print() { System.out.println(10); } } class Child extends Parent { void print() { System.out.println(20); } } Parent parent = new Child(); } </code></pre> <p>上面这段代码输出是 20.</p> <p>感觉这样很奇怪,为什么父类的构造函数调用 print 给调用到子类了呢?这样难道不是一种反直觉的结果吗?</p>
收藏(0)  分享
相关标签: 灌水交流
注意:本文归作者所有,未经作者允许,不得转载
30个回复
  • geelaw
    2022年11月17日 16:36
    #72 > 当然实际上 C++编译器不会这么没效率,就把构造函数里调用的函数当作非虚函数在编译期直接 resolve 完事。 很多时候不能这样做,因为构造函数、析构函数可以调用其他成员函数或者把 this 传入其他地方,在其他成员函数里或者通过复制的 this 调用虚函数必须仍然得到正在被构造的类的版本,而且对 this 所指向的对象用 typeid 也必须得到正在被构造的类。安全的做法是反复改变虚函数表指针。
    0 0
  • mind3x
    2022年11月17日 16:36
    多谢指出,确实不写 C++好多年了。
    0 0
  • duanguyuan
    2022年11月18日 01:36
    10 楼回答清楚明了,op 说这是打虚空打拳? 退一步讲,先不论别人回答对不对,别人花时间回答你的问题(从语气来看,并未讥讽、引战),你是给钱了还是怎么的,对别人就这么大脾气……
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 01:36
    我有啥脾气呢?你再看看我问的是什么,然后再看看 10 楼?我说他没看懂我在说什么,是在陈述事实。我跟你这种争论,如果你看懂了题,根本就不该发生。所以我说虚空打拳也是事实——你跟我争论的东西根本就是因为你在和我讨论与本帖毫无关联的内容。
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 01:36
    真正清楚明了的内容,是本帖里面 mind3x 和 geelaw 的回答,而不是 10 楼这种根本没看懂题还被同样没看懂题的人强行说好的回答。
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 01:36
    一群看不懂题的人不要在这虚空打拳和我争论浪费大家的时间,浪费版面
    0 0
  • duanguyuan
    2022年11月18日 02:06
    这里有几层逻辑不敢苟同。 ( 1 )你在题目中说 java 这种继承行为反直觉,10 楼举例“哑巴不能说话”,java 的行为反而是符合直觉的。这个例子很直观,所以这么多人给 10 楼送感谢。 ( 2 )不管哪个论坛社区,有规定看不懂题目的人不能回答问题吗?而且“看不懂题目”这还是个主观论断,或许题目不清楚,或许别人的回答是对的,只是你没 get 到 ( 3 )关于浪费版面。在大佬看来,开这个贴就是浪费版面。但有人这么说你吗?还真有,说这个问题很 low 。那你心里爽吗?你不爽。所以,别双标。我是菜鸡,我认真回个帖还是浪费版面了?
    0 0
  • llzzll1234
    2022年11月18日 02:06
    别吵了,这个 OP 不知道为什么就一股迷之傲慢,根本不是想和你们讨论问题的样子。
    0 0
  • newmlp
    2022年11月18日 02:06
    但是我在子类里有时候想调父类的方法,有时候又要调用子类的方法
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 02:06
    @ ( 1 )首先,10 楼说的内容和我的帖子没有任何关系。我是在问为什么构造函数里面调用被重写的函数,会调用到子类,然后我附了一个 C++的代码,说 C++里面,父类构造函数调用被重写的函数,调用到的是父类的方法。 10 楼回复的,是在说用父类静态类型,子类动态类型,调用静态类型被重写的方法,可以调用到子类里被重写的方法。和我说的完全没有关系。 不懂这个区别的人建议闭嘴,没必要一直争论。错就是错了,不会因为你们看不懂题目的人一直说就变成对的。 ( 2 )我没说不能回答问题,我说 10 楼没看懂题。其它没也没看懂题的人不要一直来骚扰楼主,说 10 楼是对的。讨论也是要朝着正确的方向来进行的,而不是不能指出某些人带偏了方向。 ( 3 )“在大佬看来,开这个贴就是浪费版面”。不要主观臆断,你说的没有根据。为什么楼里面 mind3x 和 geelaw 这两个大佬给出了专业性强,内容丰富的回答,而且没说这个帖子 low ,反而而有些根本没看懂题的人才会说本帖子 low 呢?是不是这些人太自恋了?还是说我指出他们看不懂题,说到他们的痛处了?真是黄钟毁弃,瓦釜雷鸣 ( 4 )“别吵了,这个 OP 不知道为什么就一股迷之傲慢,根本不是想和你们讨论问题的样子。” 你说的根本就不属实。我在和能看懂题目的人讨论问题,和他们讨论是平和的讨论的。你所谓的傲慢,是因为有些人没看懂题还来攻击我。对于这些人,我对他们回应的态度是正常的。自己错了就是错了,还逼逼赖赖的攻击对的人。
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 02:06
    统一回复:85 楼已经说的很清楚了,看不懂题的人建议不要继续在这回复我,建议去检查一下自己的认知能力。没看懂题就在这 diss 我的人我不会再回复。
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 02:06
    子类调用父类已经被子类重写的方法应该可以反射吧
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 02:36
    @ ( 1 )首先,10 楼说的内容和我的帖子没有任何关系。我是在问为什么构造函数里面调用被重写的函数,会调用到子类,然后我附了一个 C++的代码,说 C++里面,父类构造函数调用被重写的函数,调用到的是父类的方法。 10 楼回复的,是在说用父类静态类型,子类动态类型,调用静态类型被重写的方法,可以调用到子类里被重写的方法。和我说的完全没有关系。 不懂这个区别的人建议闭嘴,没必要一直争论。错就是错了,不会因为你们看不懂题目的人一直说就变成对的。 ( 2 )我没说不能回答问题,我说 10 楼没看懂题。其它没也没看懂题的人不要一直来骚扰楼主,说 10 楼是对的。讨论也是要朝着正确的方向来进行的,而不是不能指出某些人带偏了方向。 ( 3 )“在大佬看来,开这个贴就是浪费版面”。不要主观臆断,你说的没有根据。为什么楼里面 mind3x 和 geelaw 这两个大佬给出了专业性强,内容丰富的回答,而且没说这个帖子 low ,反而而有些根本没看懂题的人才会说本帖子 low 呢?是不是这些人太自恋了?还是说我指出他们看不懂题,说到他们的痛处了?真是黄钟毁弃,瓦釜雷鸣 ( 4 )“别吵了,这个 OP 不知道为什么就一股迷之傲慢,根本不是想和你们讨论问题的样子。” 你说的根本就不属实。我在和能看懂题目的人讨论问题,和他们讨论是平和的讨论的。你所谓的傲慢,是因为有些人没看懂题还来攻击我。对于这些人,我对他们回应的态度是正常的。自己错了就是错了,还逼逼赖赖的攻击对的人。
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 02:36
    有个猜想, 不知道是不是有些人智商不够,看不懂长文,也看不懂专业回答,所以不看本楼里面 mind3x 和 geelaw 这两个大佬发的真正专业的回答,而只能看 10 楼这种写给小学生看的东西,还奉为圭臬。 从给他们的点赞也能看出来,真正专业的回答只有一两个赞,10 楼这种毫无意义的回答却点赞很多。
    0 0
  • ccppgo
    2022年11月18日 02:36
    楼主估计是看到别人回答的东西简单明了, 然后看客都赞同, 他觉得看客们可能会因此觉得他水平很低 所以恼羞成怒了, 有点搞笑的
    0 0
  • JerryV2
    2022年11月18日 02:36
    C++ 的构造顺序其实是很基础的知识了,会 C++ 的人一眼就能看懂问题的所在,你说他们不懂,他们自然认为你傲慢 #72 #73 是大佬,懂 C++ 的人真是越来越少了
    0 0
  • hez2010
    2022年11月18日 02:36
    因为 Java 中的方法默认都是 virtual 的,于是 Child 的 print 把 Parent 的 print 重写了;而 C++ 的方法则默认不是 virtual 的。
    0 0
  • JerryV2
    2022年11月18日 03:06
    C++ 的构造顺序其实是很基础的知识了,会 C++ 的人一眼就能看懂问题的所在,你说他们不懂,他们自然认为你傲慢 #72 #73 是大佬,懂 C++ 的人真是越来越少了
    0 0
  • duanguyuan
    2022年11月18日 03:06
    抱歉,确实智商不够,看了 72 层 mind3x 的回答才明白 op 要问的是什么,10 楼回答确实文不对题。 打个比方,一个知识点,大家被考了 N 遍了,一遇到类似的题就知道怎么答,惯性思维。但这次的题看起来一样,问的却是另一个更深入的东西,不仔细审题自然答错。 ps: 楼主说话是真难听。
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 03:06
    专门难听给那些没看懂题就说难听话 diss 我的人看的
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 03:06
    你的分析一派胡言
    0 0
  • reallittoma
    2022年11月18日 03:06
    这帖子看下来,我认为 Java 程序员更加傲慢,绝不接受别人指出的半点 [看似] 是在说 Java [有毛病] 的言论。
    0 0
  • movq
    movq 会员 (楼主)
    2022年11月18日 03:06
    而且我也没说 Java 是劣质语言,我只是说在这一点上我觉得不符合我的直觉,结果就有些人逼逼赖赖的说什么我在秀 C++优越
    0 0
  • hez2010
    2022年11月18日 03:06
    其实 OOP 语言里也几乎只有 Java 没有写非 virtual 方法的能力。 像 C++、C# 的方法默认都是非 virtual 的,因此调用时不需要去查找虚表,反而有性能优势,只有需要 virtual 的时候才手动标记上 virtual 允许方法被重写。
    0 0
  • Opportunity
    2022年11月18日 03:36
    你说的这个反直觉的结果其实是因为你类比的有问题。 可以先从 C#/Java 的“析构”来看。C# 里用的是 `~Foo(){}`,但是可以用 `GC.SuppressFinalize(Object)` 方法来阻止这个函数被调用。Java 里这个函数就直接叫“finalize()”了。可见,这些托管语言里是不存在真正的析构函数( Destructor )的,或者说,不允许用户自定义析构的逻辑。替代品是所谓的终结器( finalizer )。 同样的,这些语言的“构造函数”其实也只是初始化器( inintializer ),虚表这些在 VM 内真正的构造阶段已经完成了,调用这些 inintializer 的时候在 VM 看来你使用的已经是一个完整的对象了。 要用 cpp 类比的话你也应该保持构造和析构函数是 trival 的,使用 inintializer 和 finalizer 来模拟构造和析构: ```cpp class Parent { public: void virtual inintialize() { print(); } void virtual print() { std::cout << "parent" << std::endl; } }; class Child : public Parent { public: void virtual inintialize() { Parent::inintialize(); print(); } void print() { std::cout << "child" << std::endl; } }; int main() { Parent *p = new Child(); p->inintialize(); p->print(); return 0; } ``` 输出 child child child 和 Java/C# 表现一致
    0 0
  • TArysiyehua
    2022年11月18日 04:36
    首先构造方法一定会调用父类的,所以 new Child () 的时候就会调用父类的没毛病,因为构造方法没有虚的,所以必须调用,不然没法继承父类的特征。 其次方法就不是,你不手动调父类的方法就相当于是覆盖了父类的方法,那自然输出的是子类的
    0 0