Java让超类返回扩展类的类型

时间:2015-01-05 10:03:43

标签: java inheritance

我目前的情况: 我有一个超类矩阵:

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方法时返回自己的对象类型?

4 个答案:

答案 0 :(得分:2)

如果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中被削弱了:您现在也可以使用子类型来使覆盖方法“更具体”。

这种方法优于泛型的优点在于它是干净的,不需要(隐式)强制转换,并且它完全限制了类型而没有任何泛型魔法。

[编辑] 现在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;
    }

答案 1 :(得分:1)

您可以scale通用。像

public class Matrix<T> {
  // ...
  public T scale(int scaleFactor) {
    // Some code that returns a scaled version of the matrix
  }
}

那么您的子类可以extend Matrix<Vector>。请注意,在scale中实际实现Matrix很困难;最好让它abstract

一样
public abstract class Matrix<T> {
  // ...
  public abstract T scale(int scaleFactor);
}

然后您的子类必须提供实现。

答案 2 :(得分:1)

您可以做的一件容易的事情就是使方法具有通用性:

public <T extends Matrix> T scale(int scaleFactor) { ... }

使用它时,您需要提供通用类型。例如,如果您想要返回Vector,则必须执行以下操作:

Matrix something = ....
Vector result = something.<Vector>scale(...);

更好的选择是制作scale方法abstract

public <T extends Matrix> T scale(int scaleFactor);

然后,在Matrix的所有子类中,您将被迫使用返回类型实现该方法,该类型是Matrix的子类型。

答案 3 :(得分:0)

你在Java中遇到了泛型类型的限制之一,如果没有在子类中重新定义public Matrix scale(int scaleFactor)然后重新定义返回类型,我就看不到简单的方法: public Vector scale(int scaleFactor)