如何访问Java基类方法?附问题演示代码
解决Java中调用基类被重写方法的问题
这是Java动态绑定(运行时多态)的典型表现——当你调用一个被重写的实例方法时,JVM会根据实际对象的类型(而不是引用变量的类型)来决定执行哪个版本的方法,所以哪怕你把A实例强转为Base引用,调用toString()还是会执行A类的实现。
要调用基类Base的toString()方法,有两种常用方案:
方案一:在子类中添加代理方法(需要修改子类)
如果可以修改子类A的代码,你可以专门加一个方法来显式调用父类的toString()实现:
class A extends Base { public String toString() { return "A"; } // 新增方法,调用父类的toString public String getBaseToString() { return super.toString(); } }
然后在测试代码中,只要把引用转回A类型(或者直接用A引用),调用这个代理方法就行:
public void test1() { A a = new A(); Base b = (Base)a; // 调用代理方法获取Base的toString结果 System.out.println(((A)b).getBaseToString()); // 输出"Base" } public void test2() { System.out.println( ((A)new A()).getBaseToString() ); // 输出"Base" }
这种方案简单直观,代码可读性高,但缺点是必须修改子类代码,如果子类是第三方类无法修改,就需要用第二种方案。
方案二:使用反射绕过动态绑定(无需修改子类)
通过Java反射API,你可以直接获取Base类中定义的toString()方法,然后强制调用它,忽略动态绑定的规则:
import java.lang.reflect.Method; class Test { public void test1() { A a = new A(); Base b = (Base)a; try { // 获取Base类的toString方法,注意要指定方法参数(这里无参数) Method baseToString = Base.class.getDeclaredMethod("toString"); // 调用方法,第一个参数是要执行方法的对象实例 String result = (String) baseToString.invoke(b); System.out.println(result); // 输出"Base" } catch (Exception e) { e.printStackTrace(); } } private String testB(Base b) { try { Method baseToString = Base.class.getDeclaredMethod("toString"); return (String) baseToString.invoke(b); } catch (Exception e) { e.printStackTrace(); return null; } } public void test2() { System.out.println( testB(new A()) ); // 输出"Base" } }
反射的优点是不需要修改任何原有类的代码,但缺点是代码相对繁琐,而且会失去编译时的类型检查,需要处理异常,性能也会比直接调用方法稍差一些。
补充说明
需要注意的是,Java语言本身并没有提供直接从外部调用父类被重写方法的语法(比如类似b.Base::toString()这种),所以上面两种是最常用的解决方案。根据你的实际场景选择:如果能修改子类,优先用方案一;如果不能修改子类,就用反射方案。
内容的提问来源于stack exchange,提问作者datafiddler
相关产品推荐
相关产品推荐

