Java let superclass return 扩展类型 class

Java let superclass return type of extended class

我现在的情况: 我有一个超级class矩阵:

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 class 扩展,它具有一些特定于向量的方法(例如计算向量的长度)。

现在,假设我有一个名为的矢量对象,我想按某个系数缩放它。然后我会调用 vector.scale(1234); 这会产生一个矩阵对象。

但是,我希望结果是矢量对象。我当然可以覆盖 Vector class 中的缩放方法并将 superclass 的结果转换为 Vector class 的对象,但这似乎不是正确的方法去做这个。

任何人都可以给我一些关于如何实现它的指示,以便我可以扩展 Matrix class 并拥有子 classes return 自己类型的对象他们什么时候调用缩放方法?

您可以使 scale 通用。喜欢

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

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

可能更好
public abstract class Matrix<T> {
  // ...
  public abstract T scale(int scaleFactor);
}

然后你的子类必须提供一个实现。

您可以做的一件简单的事情就是使方法通用:

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

使用时需要提供泛型。例如,如果你想 Vector 被 returned,你必须做:

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

更好的选择是使 scale 方法 abstract:

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

然后,在 Matrix 的所有子类中,您将被迫使用属于 Matrix 的子类型的 return 类型来实现该方法。

如果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 中被削弱:您现在也可以使用子类型来创建重写方法 "more specific."

这种方法相对于泛型的优势在于它很干净,不需要(隐式)强制转换,并且它精确地限制了类型而没有任何泛型魔法。

[编辑] 现在 Vector 只是一种特殊的 Matrix (1-column/row 类型),这意味着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;
    }
}

如果class是不可变的(很可能应该是),那么你需要使用拷贝构造函数,当然:

    public Matrix scale(int scaleFactor) {
        Matrix result = new Matrix(this);
        result.doScale(scaleFactor);
        return result;
    }

您有点触及 Java 中泛型类型的限制之一,如果不在子类中重新定义 public Matrix scale(int scaleFactor) 然后重新定义,我认为没有简单的解决方法- 定义 return 类型:public Vector scale(int scaleFactor).