Java中基类方法如何返回派生类对象 链式调用报错求解
报错原因
报错的核心是Java编译期静态类型检查机制:
- 基类
Base的set_x方法声明的返回值类型为Base,即便你用Derived实例调用该方法、运行时实际返回的是Derived对象,编译阶段只会识别返回值的静态类型为Base,而Base类中没有定义print_x_y()方法,因此编译不通过。
解决方案
下面给出两种常用的可长期使用的方案,以及一种应急临时方案:
方案1:重写基类方法使用协变返回类型
Java 5及以上版本支持协变返回类型,子类重写父类方法时可以返回比父类更具体的子类型,直接在Derived类中重写继承自基类的链式方法即可:
class Derived extends Base { int y_of_derived_class = 89; // 重写父类set_x方法,返回Derived类型 @Override public Derived set_x(int x) { super.set_x(x); return this; } // 如果需要链式调用print_x后的派生类方法,也可以同步重写print_x @Override public Derived print_x() { super.print_x(); return this; } // 原有派生类方法保持不变 public Derived print_y() { System.out.printf("Y of Derived Class = %d\n", this.y_of_derived_class); return this; } public Derived print_x_y() { print_x(); print_y(); return this; } public Derived set_x_y(int x, int y) { x_of_base_class = x; y_of_derived_class = y; return this; } }
修改后obj.set_x(78).print_x_y()可直接正常运行,该方案适合继承层级少、基类链式方法不多的场景。
方案2:泛型基类实现
如果有多层继承、不想每个子类都重复重写所有基类链式方法,可以把基类定义为泛型类,泛型参数指定为实际子类类型:
// 泛型基类,T为实际子类类型 class Base<T extends Base<T>> { int x_of_base_class = 10; public T print_x() { System.out.printf("X of Base Class = %d\n", this.x_of_base_class); return (T) this; } public T set_x(int x) { x_of_base_class = x; return (T) this; } } // 派生类传入自身作为泛型参数 class Derived extends Base<Derived> { int y_of_derived_class = 89; public Derived print_y() { System.out.printf("Y of Derived Class = %d\n", this.y_of_derived_class); return this; } public Derived print_x_y() { print_x(); print_y(); return this; } public Derived set_x_y(int x, int y) { x_of_base_class = x; y_of_derived_class = y; return this; } }
该方案无需在子类重写基类方法,所有基类方法天然返回子类类型,支持直接链式调用派生类方法。
临时应急方案:强制类型转换
如果不想修改原有类定义,可以在调用时手动强制转换类型,不过需要确保运行时返回的确实是Derived实例,否则会抛出类型转换异常:
((Derived)obj.set_x(78)).print_x_y();
该方案健壮性差,仅适合临时调试使用,不建议在生产代码中使用。
内容的提问来源于stack exchange,提问作者Aman Rathore
相关产品推荐
相关产品推荐

