在抽象java类中正确使用泛型? [英] Proper use of generics in abstract java class?

查看:40
本文介绍了在抽象java类中正确使用泛型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:这个问题措辞不好,提供的答案从字面上看是正确的,但没有教我如何达到我所需要的.如果您遇到同样的问题,这最终帮助了我:当这些方法的返回类型取决于子类时,如何强制执行子类行为/方法?

EDIT: This question is not well worded, and the provided answer is correct in a literal sense but did not teach me how to attain what I needed. If you are struggling with the same problem, this is what finally helped me: How to enforce child class behavior/methods when the return types of these methods depends on the child class?

我正在尝试从我编写的样板抽象类中实现一个基本的矩阵类.这个抽象类将有多个实现,每个实现都使用不同的数学库,然后我将测试速度.

I am trying to implement a basic matrix class from a boilerplate abstract class I wrote. There will be several implementations of this abstract class, each one using a different math library, which I will then test for speed.

每个实现都将其数据保存在该库的本机矩阵数据结构中.我认为这是泛型的一个用例.在这一点上,我想我已经阅读了太多教程并观看了太多视频,因为我似乎无法找出放置 T 符号的所有正确位置以使其正常工作.

Each implementation will hold its data in that library's native matrix data structure. I think this is a use case for generics. At this point I think I've read too many tutorials and watched too many videos, as I just can't seem to figure out all the right places to put the T Notation to make this work correctly.

所以我的问题是双重的:

So my question is twofold:

  1. 我是否误用或错过了泛型的要点?
  2. 如果不是,使用它们的正确语法是什么?

我已经阅读了文档以及大约三个不同的教程,但仍然无法理解.

I've read the docs plus about three different tutorials and still can't understand.

这是我尝试过的:

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);

这是我的实现:

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;
    }

错误是:Method没有覆盖其超类中的方法.

推荐答案

将其数据保存在该库的本机矩阵数据结构中.我认为这是泛型的一个用例.

hold its data in that library's native matrix data structure. I think this is a use case for generics.

泛型用于链接事物.您使用 <T> 声明了类型变量,并且就粘贴而言,您已经在一个地方(T 类型的字段)中使用了它.这是一个危险信号;一般来说,考虑到它链接事物,如果你只在一个地方使用它通常是一个不好的迹象.

Generics serves to link things. You declared the type variable with <T>, and you've used it in, as far as your paste goes, exactly one place (a field, of type T). That's a red flag; generally, given that it links things, if you use it in only one place that's usually a bad sign.

这就是我的意思:想象一下,你想写一个方法,它说:这个方法接受 2 个参数并返回一些东西.这段代码并不特别关心你在这里折腾什么,但是,参数必须是相同的类型,我也返回那种类型的东西.您希望将参数的类型、另一个参数的类型和返回类型链接在一起.

Here's what I mean: Imagine you want to write a method that says: This method takes 2 parameters and returns something. This code doesn't particularly care what you toss in here, but, the parameters must be the same type and I return something of that type too. You want to link the type of the parameter, the type of the other parameter, and the return type together.

就是泛型的用途.

如果我们稍微扭曲一下想法,它可能适用于这里:您想将 data 字段的类型与 BaseMatrix 的某些特定实现只能对某些特定类型进行操作的概念相关联,例如ND4J矩阵.

It may apply here, if we twist our minds a bit: You want to link the type of the data field to a notion that some specific implementation of BaseMatrix can only operate on some specific type, e.g. ND4JMatrix.

然而,大多数情况下,不,这并没有让我觉得正确使用泛型.你可以很容易地完全避免它:只需..停止使用 private T data; 字段.你在这里有什么好处?您不知道是什么类型,您甚至不知道它是否可序列化.你对此一无所知,编译器证实了这一点:你可以对那个对象做任何事情,除了你可以对所有通常很无趣的对象做的事情.你可以在它上面调用 .toString() ,在它上面同步,或者调用 .hashCode(),就是这样.

However, mostly, no, this doesn't strike me as proper use of generics. You can avoid it altogether quite easily: Just.. stop having that private T data; field. What good is it doing you here? You have no idea what type that is, you don't even know if it is serializable. You know nothing about it, and the compiler confirms this: There is absolutely not one iota you can do with that object, except things you can do to all objects which are generally quite uninteresting. You can call .toString() on it, synchronize on it, maybe invoke .hashCode(), that's about it.

为什么不直接放弃那个领域?实现可以使字段,不需要它在基础!

Why not just ditch that field? The implementation can make the field, no need for it to be in base!

public class ND4JDense extends BaseMatrix {
    private ND4JMatrix data; // why not like this?
}

(此代码假定 'ND4JMatrix' 是您在此处所需的正确数据类型,这可能是 ND4J impl 中数据的内部表示).

(This code assumes 'ND4JMatrix' is the proper data type you desire here, a thing that can is the internal representation for the data in the ND4J impl).

但是,如果必须的话,是的,您可以在这里使用泛型.您已经对 BaseMatrix 进行了类型修改,这意味着 BaseMatrix 的所有用法都必须参数化.那是你在代码中搞砸的部分.如果我们采用类型参数化 BaseMatrix 类和 T 类型字段的计划,正确的代码是:

However, if you must, yeah, you can use generics here. You've type-varred BaseMatrix, and that means all usages of BaseMatrix must be parameterized. That's the part you messed up in your code. If we go with your plan of a type-parameterized BaseMatrix class and a field of type T, the right code is:

public class ND4JDense extends BaseMatrix<ND4JMatrix> {
   ...
}

然而,我不会这样做(我会选择让 impl 拥有该领域,简单得多,不需要用泛型来打扰任何人).当然,除非您确实对该字段有实际需求并且它是 BaseMatrix 的 API 的一部分.例如,如果你想要这个:

I wouldn't, however, do it this way (I'd go with having the impl have the field, much simpler, no need to bother anybody with the generics). Unless, of course, you DO have an actual need for that field and it IS part of BaseMatrix's API. For example, if you want this:

public class BaseMatrix<T> {
    public T getData() { return data; }
}

然后它开始变得更有意义.有了它,您可以编写以下内容,它们都可以编译并运行良好:

then it starts to make more sense. With that, you can write the following and it'll all compile and work great:

public class ND4JDense extends BaseMatrix<ND4JMatrix> {
    ...
    // no need to write a getData method here at all!
    ...
}

ND4JDense dense = new ND4JDense();
ND4JMatrix matrix = dense.getData();

但是,很明显,如果您打算让 ND4JMatrix 保留 BaseMatrix API 的用户可能不应该接触的实现细节,那么这毫无意义.

But, clearly, this makes no sense if you intend for the ND4JMatrix to remain an implementation detail that users of the BaseMatrix API should probably not be touching.

你后来改变了我的问题.现在您希望 mmul 方法将 'self' 作为参数,有效地:您希望传入相同的类型.

You changed the question on me, later. Now you want the mmul method to take 'self' as argument, effectively: You want the same type to be passed in.

你可以这样做,但这有点棘手.您需要 self-ref 泛型 hack.它看起来像这样:

You can sort of do that but it is a little tricky. You need the self-ref generics hack. It looks like this:

public class BaseMatrix<T extends BaseMatrix<T>> {
   public abstract T mmul(T other);
}

在实践中,T 的唯一有效值是您自己的类,或者至少,这是意图.这工作正常:

In practice the only valid value for T is your own class, or at least, that is the intent. This works fine:

public class ND4JDenseMatrix extends BaseMatrix<ND4JDenseMatrix> {
    public ND4JDenseMatrix mmul(ND4JDenseMatrix other) {
      .. impl here ..
    }
}

这篇关于在抽象java类中正确使用泛型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆