如何使用泛型类作为参数并扩展类型?

时间:2019-04-10 17:02:28

标签: java generics

我试图在我的项目中使用泛型,以具有可以利用不同类型的对象的基类。但是在某些情况下尝试将这些通用类型的类作为参数传递时,我遇到了麻烦。

所以我想我的问题是,有没有办法使用某个通用类型的接口并传入该通用类型的扩展?

很抱歉,我的措辞很奇怪,我不太习惯尝试解释这些类型的问题。我很高兴对泛型有某种了解,我觉得我无法掌握它们的真正工作原理。我已经阅读了很多关于它们的文章,但是找不到描述我的问题或真正帮助我理解所有问题的文章。

在扩展通用类型T时,我尝试了许多变体,也尝试使用通配符。但是我总是总是以许多嵌套的泛型和通配符的捕获而告终,我只是一团糟。

我有这个界面:

public interface NiceObject<T extends SomeClass> {}

然后我希望能够通过不同的实现对其进行扩展:

public class EpicClass extends SomeClass {}
public class CoolObject implements NiceObject<EpicClass> {}

这对我来说很好,但是当我尝试将NiceObject的实现作为类型NiceObject<T>的参数传递时,其中T是SomeClass的扩展,它告诉我该类型不适用。

public void coolMethod(NiceObject<SomeClass> obj);
CoolObject obj = new CoolObject();
coolMethod(obj);
// this does not work

我还尝试过以某些方式更改方法:

public void coolMethod(NiceObject<?> obj);

public void coolMethod(NiceObject<? extends SomeClass> obj);

public <S extends SomeClass> void coolMethod(NiceObject<S> obj);

// None of these produce my desired result
// I just end up with non-applicable parameters somewhere in my program.

编辑 我会尝试使我的问题更清楚:

NiceObject<EpicClass> obj = new CoolObject();
coolMethod(obj);

// Message:
// The method coolMethod(NiceObject<SomeClass>) in the type NiceMethods
// is not applicable for the arguments (NiceObject<EpicClass>)

让我感到困惑的是,EpicClass显然是SomeClass的扩展,编译器不应该能够接受它作为SomeClass的原因,因为它继承了与coolMethod()相同的属性?

编辑2 看来我现在已经解决了我的问题。在发布有关该问题的信息后,我倾向于解决我的问题。

如所提出的评论,更多的是它在程序其他部分引起的问题。我不想混入程序的其他部分,因为它的结构以及我对泛型的过度使用都是愚蠢的,并且我不想使其变得更加混乱。

当我修改NiceObject<SomeClass>以使其能够接受任何种类的NiceObject时,出现了其他问题。我在NiceObject中有一些方法必须使用它自己的public interface NiceObjectUser <N extends NiceObjectUser<N>> { public N getSelf(); } 类型作为参数。我通过创建一个将返回自身并由子类型实现的方法来解决了这个问题。

.not()

我也做了其他愚蠢的事情来使错误消失,并且我不得不重构很多其他的类。最后,它无论如何都可以工作。

我很感谢这个答案,它解释了一些我现在接受的关于泛型的东西。我现在觉得我对泛型有更高的理解。

1 个答案:

答案 0 :(得分:0)

这里的问题是,即使EpicClassSomeClass的子类型,NiceObject<EpicClass>也是NiceObject<SomeClass>的子类型。要了解原因,请考虑:

class Box<T> {
  private T value;
  T get() {
    return value;
  }

  void set(T value) {
    this.value = value;
  }
}

现在考虑两个类,例如ObjectString,其中StringObject的子类型。假设我们允许Box<String>Box<Object>的子类型。这意味着您可以在期望Box<String>的任何地方使用Box<Object>。现在考虑这样的代码:

Box<String> stringBox = new Box<String>();
Box<Object> objectBox = stringBox;
objectBox.set(new NonStringObject());
String string = stringBox.get(); // Error! Got a NonStringObject() from a string box!

通常,一个盒子可能会消费一个T产生一个T的事实意味着子类型规则不起作用。您可能期望的方式。通常,您发布的替代方案是遇到此类问题时的解决之道。为了弄清楚他们为什么不工作,我们将不得不更多地了解您要执行的操作的详细信息。