在抽象java类中正确使用泛型?
编辑:这个问题措辞不恰当,提供的答案在字面意义上是正确的,但没有教会我如何获得所需。如果你正在为同样的问题挣扎,这就是最终帮助我的原因: 我试图从我编写的样板抽象类实现一个基本矩阵类。这个抽象类将有几个实现,每个都使用不同的数学库,然后我将测试它们的速度 每个实现都将其数据保存在该库的本机矩阵数据结构中。我认为这是泛型的一个用例。在这一点上,我认为我已经阅读了太多的教程和观看了太多的视频,因为我似乎无法找出所有正确的位置来放置在抽象java类中正确使用泛型?,java,generics,abstract-class,Java,Generics,Abstract Class,编辑:这个问题措辞不恰当,提供的答案在字面意义上是正确的,但没有教会我如何获得所需。如果你正在为同样的问题挣扎,这就是最终帮助我的原因: 我试图从我编写的样板抽象类实现一个基本矩阵类。这个抽象类将有几个实现,每个都使用不同的数学库,然后我将测试它们的速度 每个实现都将其数据保存在该库的本机矩阵数据结构中。我认为这是泛型的一个用例。在这一点上,我认为我已经阅读了太多的教程和观看了太多的视频,因为我似乎无法找出所有正确的位置来放置t符号,以使其正确工作 所以我的问题有两个: 我是否误用或错过了泛型的
t
符号,以使其正确工作
所以我的问题有两个:
public abstract class BaseMatrix<T> {
protected int[] shape;
protected int nrows;
protected int ncols;
protected T data; // <--- Here is the generic data --->
public BaseMatrix(int rows, int cols){
this.nrows = rows;
this.ncols = cols;
this.shape = new int[]{nrows, ncols};
}
public abstract BaseMatrix mmul(BaseMatrix other);
公共抽象类BaseMatrix{
受保护的int[]形状;
受保护的内部流动;
受保护的int NCOL;
受保护的T数据;//
公共基矩阵(int行,int列){
this.nrows=行;
this.ncols=cols;
this.shape=newint[]{nrows,ncols};
}
公共摘要BaseMatrix mmul(BaseMatrix其他);
以下是我的实现:
public class ND4JDenseMatrix extends BaseMatrix{
// private INDArray data;
public ND4JDenseMatrix(int rows, int cols) {
super(rows, cols);
this.data = Nd4j.zeros(this.shape); <--- Here is the non-generic data --->
}
@Override
public ND4JDenseMatrix mmul(ND4JDenseMatrix other) {
ND4JDenseMatrix result = new ND4JDenseMatrix(nrows, ncols);
result.data = data.mmul(other.data);
return result;
}
公共类ND4JDenseMatrix扩展了BaseMatrix{
//私有阵列数据;
公共ND4JDENSE矩阵(int行,int列){
超级(行、列);
this.data=Nd4j.zero(this.shape);
}
@凌驾
公共ND4JDenseMatrix mmul(ND4JDenseMatrix其他){
ND4JDenseMatrix结果=新的ND4JDenseMatrix(nrows,ncols);
result.data=data.mmul(其他数据);
返回结果;
}
错误是:方法不重写其超类中的方法。
将其数据保存在该库的原生矩阵数据结构中。我认为这是泛型的一个用例
泛型用于链接事物。您用
声明了类型变量,并且在粘贴过程中只在一个地方使用了它(一个字段,类型为T)。这是一个红旗;一般来说,考虑到它链接事物,如果只在一个地方使用它,这通常是一个不好的标志
我的意思是:假设你想写一个方法,它说:这个方法接受2个参数并返回一些东西。这段代码并不特别关心你在这里输入了什么,但是,这些参数必须是相同的类型,我也返回那种类型的东西。你想链接参数的类型,另一个参数的类型,以及一起返回类型
这就是泛型的作用
如果我们稍微绞尽脑汁,它可能适用于这里:您希望将数据
字段的类型链接到一个概念,即BaseMatrix的某些特定实现只能在某些特定类型上运行,例如ND4JMatrix
然而,大多数情况下,不,这对我来说不是泛型的正确使用。你可以很容易地避免它:只是..停止使用私有t数据;
字段。这对你有什么好处?你不知道那是什么类型,你甚至不知道它是否可序列化。你对它一无所知,编译器c确认这一点:除了可以对所有对象执行的通常都很无趣的操作外,您绝对不能对该对象执行任何操作。您可以对其调用.toString()
,对其进行同步,或者调用.hashCode()
,仅此而已
为什么不干脆把那块地扔掉呢?实施可以让这块地变得更大,不需要它在基地里
public class ND4JDense extends BaseMatrix {
private ND4JMatrix data; // why not like this?
}
(这段代码假设“ND4JMatrix”是您在这里想要的合适的数据类型,可以是ND4J impl中数据的内部表示)
但是,如果必须的话,是的,您可以在这里使用泛型。您已经键入varred BaseMatrix,这意味着BaseMatrix的所有用法都必须参数化。这就是您在代码中弄乱的部分。如果我们按照您的计划使用类型参数化BaseMatrix类和类型T字段,正确的代码是:
public class ND4JDense extends BaseMatrix<ND4JMatrix> {
...
}
实际上,T的唯一有效值是您自己的类,或者至少是意图。这很好:
public class ND4JDenseMatrix extends BaseMatrix<ND4JDenseMatrix> {
public ND4JDenseMatrix mmul(ND4JDenseMatrix other) {
.. impl here ..
}
}
公共类ND4JDenseMatrix扩展了BaseMatrix{
公共ND4JDenseMatrix mmul(ND4JDenseMatrix其他){
在这里。。
}
}
据我所知,您的代码中有两个问题:
mmul
。要正确重写该方法,方法签名必须匹配,特别是输入参数必须相同。可以使用返回类型的子类型,如Java支持协变
。如果您在tead放入了它的一个子类,即重载。希望您能理解其中的区别。因此正确的签名可以是以下内容:公共基矩阵mmul(基矩阵其他){ …
}
T
,因此编译器无法根据假设知道它是BaseMatrix
的子类型。它可以是任何类型,例如对象,因此您将得到“method not found”编译错误
请注意您在线上得到的警告
extensedbasematrix
。非常肯定mmul()
应该在抽象类中返回T
。@chrylis小心光学-这有点类似于@Override警告:类“ND4JDenseMatrix”必须声明为抽象或实现抽象方法“mmul(BaseMatrix)”'在'BaseMatrix'
中。我肯定没有正确地实现mmul抽象类……但我无法实现
public class ND4JDense extends BaseMatrix<ND4JMatrix> {
...
// no need to write a getData method here at all!
...
}
ND4JDense dense = new ND4JDense();
ND4JMatrix matrix = dense.getData();
public class BaseMatrix<T extends BaseMatrix<T>> {
public abstract T mmul(T other);
}
public class ND4JDenseMatrix extends BaseMatrix<ND4JDenseMatrix> {
public ND4JDenseMatrix mmul(ND4JDenseMatrix other) {
.. impl here ..
}
}