如何调用父类被重写的方法?toString()重写调用疑问
如何在子类重写toString后调用父类的实现?
这个问题我太熟悉了,Java的动态绑定机制在这里很容易让人困惑,先帮你梳理清楚整个场景和解决方案~
首先先还原你给出的类定义和JShell测试结果:
你的类代码
class Point { int x; int y; Point(int x, int y) { this.x = x; this.y = y; } public String toString() { return String.format("(%d,%d)",x,y); } } class Line extends Point { int l; Line(int x, int y, int l) { super(x,y); this.l = l; } public String toString() { return String.format("Length is %d", this.l); } }
JShell测试中的关键现象
你发现即使把Line对象强转成Point类型调用toString(),返回的依然是Line类的实现:
((Point) l).toString() ==> "Length is 3"
这是因为Java的实例方法调用是动态绑定的——运行时会根据对象的实际类型(而不是引用的声明类型)来决定调用哪个方法。所以不管你用Point还是Line的引用指向这个对象,只要实际对象是Line,就会调用Line重写后的toString()。
解决方案:调用父类Point的toString()方法
想要绕开动态绑定调用Point的toString(),有两种常用方式:
方式1:在子类Line中添加专门的方法(推荐)
直接在Line类里新增一个方法,通过super关键字调用父类的toString():
class Line extends Point { // 已有的属性、构造方法、toString()... public String getPointToString() { return super.toString(); // 直接调用父类的toString实现 } }
之后调用时,只要把引用转成Line类型调用这个方法即可:
Point p = new Line(0,1,3); System.out.println(((Line)p).getPointToString()); // 输出:(0,1)
方式2:使用反射(不推荐,仅当无法修改Line类时使用)
如果没办法修改Line的代码,可以用反射直接调用Point类的toString()方法,绕开动态绑定机制:
import java.lang.reflect.Method; public class Test { public static void main(String[] args) throws Exception { Point p = new Line(0,1,3); // 获取Point类的toString方法 Method pointToStringMethod = Point.class.getDeclaredMethod("toString"); // 调用该方法,传入对象实例 String result = (String) pointToStringMethod.invoke(p); System.out.println(result); // 输出:(0,1) } }
反射的缺点是代码可读性差,而且会带来额外的性能开销,所以优先用第一种方式。
内容的提问来源于stack exchange,提问作者Rayshaun Thompson
相关产品推荐
相关产品推荐

