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)