咨询一个继承、重载、父类、多态的方法调用问题

2022-01-30 17:02:18 +08:00
 cpstar

遇到一个问题,需要外部调用父类的方法,怎么搞?

class Father {
	public void name() {
		System.out.println("father");
	}
}

class Son extends Father {
	public void name() {
		System.out.println("son");
	}
}

如果 new Son()的话,

Son a = new Son();
Father b = new Son();

甭管 a 还是 b ,调用 name()都会显示 son 。

有没有什么办法,使得 b 调用 name()得到 father ?

BTW ,Son 可能还有其他方法需要 b 来调用。 再 BTW ,不限于使用反射来搞定。

3554 次点击
所在节点    Java
39 条回复
golangLover
2022-01-30 17:46:24 +08:00
在 son 里面写 super.name()
cpstar
2022-01-30 18:13:08 +08:00
@golangLover 必须是 b 调用,外部调用,不是内部
Building
2022-01-30 18:35:19 +08:00
这是一个类调用同一个方法返回不同结果了啊,无解的,调用同一个方法返回的东西一定是一样的。
littlewing
2022-01-30 18:36:27 +08:00
貌似没办法
换 C++ 吧
golangLover
2022-01-30 18:48:56 +08:00
@cpstar 那不会了。为什么提供多一个不同名的方法不行呢?
Jooooooooo
2022-01-30 18:49:30 +08:00
感觉是 xy 问题啊, 要不细说说究竟是什么场景需要这样.
ccde8259
2022-01-30 19:19:21 +08:00
首先得让 Father 去实现一个具有 name 方法的 interface ,然后是反射重写对象头把 Son 实例的 Class ptr 指向 Father 。
lsry
2022-01-30 19:30:37 +08:00
如果是想让 father 调用自己的方法(以变量定义时候的类型,而不是实际类型),可以将方法前面加 static 。
Leviathann
2022-01-30 19:59:55 +08:00
子类型是新的类型啊
又不是 javascrpit 存了父类型的原型
SoloCompany
2022-01-30 20:38:18 +08:00
简单来说是不可能的, 你必须修改 A (父类) 或 B (子类) 提供一个非多态的 alias 才能调用到
SoloCompany
2022-01-30 20:41:13 +08:00
再详细一些, 反射只能 hack field / method 的不可见或不可访问的问题而无法 hack method 因多态而 hidden 的问题, 真实的 hack 只能把想调用的方法重新写一次, 可以利用反射越过无法访问的 filed / method
bigbyto
2022-01-30 20:42:26 +08:00
invokedymanic 可以实现,不过尽可能不要这样做。
crayygy
2022-01-30 20:45:29 +08:00
外部有什么必须要调用父类方法的理由吗?一般涉及到这类很 tricky 的问题的时候从需求侧开始思考问题比较合适,也许有更合适的其他方法
251
2022-01-30 21:20:12 +08:00
既然重写了 name(),就说明 son.name()能完全代替 father.name()的功能,所以不需要调 father.name().如果不能完全替代,说明 father.nameson.name() 功能不一样,那就不要重写了。C++ 应该可以,java 不知道。
251
2022-01-30 22:04:17 +08:00
刚才又想了一下,肯定行。但这个问题有点无聊了,a 跟 b 是同一个对象,同一个对象调用签名一样的方法,jvm 默认调第二方法,但你又想掉第一个?好比 两个都叫翠花,你就叫一声翠花,鬼知道你想默认调用那个翠花?你可能想要的是想通过声明的方式不同以改变调用不用的方法,那你自己把字节码编译好,用 classloader 的 defineclass 加载,肯定可以。
pptom
2022-01-30 22:22:36 +08:00
这就是多态啊,只有运行时才确定对象是哪个类的实例。不理解这个问题的意义
EvanLuo42
2022-01-30 22:23:58 +08:00
所以为什么要 b 调 a ,这样做用继承又有什么用。你 b 单方面的调用一个子类,从我的观点来看违背了 oop 的思想。
Jwyt
2022-01-30 22:38:31 +08:00
单看代码你直接 new Father() 不就完了
cpstar
2022-01-30 22:56:57 +08:00
@littlewing 4# 提问题之前搜了一下,说到了 C++可以 upcast 到父类,就能用父类的方法覆盖子类。然后就想起来当初学习 JAVA 时,就说 C++不纯粹面向对象,这就是其中一个问题,做不到这个层面的多态。
cpstar
2022-01-30 23:05:26 +08:00
@251 15# 我感觉也应该行,而且我还知道 jvm 上,类加载之后,除了子类加载到内存中并且具有方法指针入口,父类也会加载到内存里,只不过多态调用的时候,实例中的方法入口指针指向的是子类的(因为实例是子类的),所以我在问题里提到了反射(反射没有系统学过,不太清楚怎么用)。

按照 @SoloCompany 11#,我能理解反射能够做到的,也仅是“类”这个层面的,再结合 @bigbyto 12#提到的 invokedynamic ,这个应该是需要渗透到 jvm 层面操控“实例”来搞定了(比如修改实例的方法入口指针),某种程度上应该就是 reflect jvm 。擦,怎么感觉有点像 matrix 了,neo 要苏醒,囧 rz 。。。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/831432

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX