Java让超类返回扩展类的类型
我目前的情况:我有一个超类矩阵:
public class Matrix { private final float[] values; private final int numberOfRows; private final int numberOfColumns; public Matrix(int rows, int columns, float... values) { this.values = new float[numberOfRows * numberOfColumns]; this.numberOfRows = numberOfRows; this.numberOfColumns = numberOfColumns; System.arraycopy(values, 0, this.values, 0, values.length); } public Matrix scale(int scaleFactor) { //Some code that returns a scaled version of the matrix } }
它由Vector类扩展,具有一些特定于矢量的方法(例如计算矢量的长度)。
现在,假设我有一个名为的矢量对象,我想通过某种因素来缩放它。 然后我会调用vector.scale(1234);
这导致了一个矩阵对象。
但是,我希望结果是一个矢量对象。 我当然可以覆盖Vector类中的scale方法,并将超类的结果强制转换为Vector类的对象,但这似乎不是正确的方法。
任何人都可以给我一些关于如何实现这一点的指示,以便我可以扩展Matrix类并让子类的对象在调用scale方法时返回它们自己的对象类型?
如果Vector extends Matrix
,您可以:
public class Matrix { public Matrix scale(int scaleFactor) { ... return Matrix ... } } public class Vector extends Matrix { ... @Override public Vector scale(int scaleFactor) { // <-- return sub type here! ... return Vector ... } }
在Java 5中,被覆盖的方法必须具有相同类型的规则已被削弱:您现在可以使用子类型来使覆盖的方法“更具体”。
这种方法优于generics的优点在于它是干净的,不需要(隐式)转换,并且它在没有任何generics魔法的情况下完全限制了类型。
[编辑]现在, Vector
只是一种特殊的Matrix
(1列/行类型),这意味着scale()
中的代码是相同的。
不幸的是,这不起作用:
public class Vector extends Matrix { ... @Override public Vector scale(int scaleFactor) { // <-- return sub type here! return (Vector) super.scale(scaleFactor); } }
因为您无法将Matrix
实例转换为Vector
。 解决方案是将比例代码移动到辅助方法中:
public class Matrix { protected void doScale(int scaleFactor) { ... original scale() code here... } public Matrix scale(int scaleFactor) { doScale(scaleFactor); return this; } } public class Vector extends Matrix { ... @Override public Vector scale(int scaleFactor) { doScale(scaleFactor); return this; } }
如果类是不可变的(它可能应该是),那么你需要使用复制构造函数,当然:
public Matrix scale(int scaleFactor) { Matrix result = new Matrix(this); result.doScale(scaleFactor); return result; }
你可以使scale
通用。 喜欢
public class Matrix { // ... public T scale(int scaleFactor) { // Some code that returns a scaled version of the matrix } }
那么你的子类可以extend Matrix
。 注意,在Matrix
实际实现scale
是很困难的; 把它abstract
得更好可能更好
public abstract class Matrix { // ... public abstract T scale(int scaleFactor); }
然后你的子类必须提供一个实现。
您可以做的一件容易的事情是使方法通用:
public T scale(int scaleFactor) { ... }
使用它时,您需要提供通用类型。 例如,如果要返回Vector
,则必须执行以下操作:
Matrix something = .... Vector result = something.scale(...);
更好的选择是使scale
方法abstract
:
public T scale(int scaleFactor);
然后,在Matrix
所有子类中,您将被迫使用返回类型实现该方法,该返回类型是Matrix
的子类型。
你有点像Java中的generics类型的限制之一,如果没有在子类中重新定义public Matrix scale(int scaleFactor)
然后重新定义返回类型,我看不出简单的方法: public Vector scale(int scaleFactor)
。