通用误解:尝试添加到列表时

huangapple go评论144阅读模式
英文:

generic misunderstanding when tying to add to list

问题

以下是您要求的代码部分的中文翻译:

这是一个通配符问题

我的目的是创建一个包含具有泛型类型的类的列表并提供扩展示例

这是结构

public class Event<T extends ActionType> {
}

public abstract class ActionType {
}

// **许多**扩展ActionType类的类

这是一个包含扩展自**ActionType**的类的列表

private List<Event<ActionType>> list = new ArrayList<>();

Event<RightClick> event = new Event<>(xPosition, yPosition, delay, new RightClick(robot), clicks, robot);

list.add(event);

我知道这样做无法确保我可以添加扩展的项

private List<Event<ActionType>> list = new ArrayList<>();

但我可以采取什么措施将项目添加到同一列表中

为了解决我的问题我使用了通配符选择器**?**

List<Event<? extends ActionType>>
英文:

this a wildcard question.

my purpose is to make a list that contains a class that has a generic type with extended examples:

so this is the structure:

  public class Event<T extends ActionType>{
  }

  public abstract class ActionType{
  }

  //**many** classes that extends ActionType class

that's a list that hold classes that extends from ActionType

  private List<Event<ActionType>> list = ArrayList<>();

  Event<RightClick> event = new Event<>(xPosition, yPosition, delay, new RightClick(robot), clicks, robot);

  list.add(event);

I know that's I cant do this to make sure that I can add the extended items:

  private List<Event<ActionType>> list = ArrayList<>();

but what I can do to add the items to the same list.

to fix my problem I used the wildcard selector ?

 List<Event<? extends ActionType>>

答案1

得分: 1

Explanation

泛型是不变的List<Event<ActionType>> 不会接受 Event<RightClick>,只会接受 Event<ActionType>

理解泛型并调整你的泛型类型限制。

如果泛型是协变的,那么你可以把一个期望 List<Animal> 的人一个 List<Dog>,然后再向其中添加 Cat,这将导致堆破坏,因为 dogs.get(0) 可能突然变成了一个 Cat

一个例子:

List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());

List<Animal> animals = dogs; // 假装这能够工作
animals.add(new Cat()); // 将是合法的

Dog dog = dogs.get(1); // 应该是安全的,但却是猫,堆破坏

List<Animal> 明确表示这个列表必须接受所有动物,包括猫。但是 List<Dog> 只限制在狗。这两个列表的行为不同,它们有不同的限制,因此你不能将一个用于另一个。与DogAnimal不同,List<Dog> 不是一个 List<Animal>,这就是共变和不变的含义。


Solution

正确的工具用于*“接受任何 ActionType,我不关心是什么”*是通配符。所以要么使用

List<Event<? extends ActionType>>

要么只使用

List<Event<?>>

因为 Event 类已经指定了 T extends ActionType 的限制。

使用这种类型,你将能够向其中添加各种类型的 Event

Event<RightClick> rightClick = ...
Event<LeftClick> leftClick = ...
Event<MiddleClick> middleClick = ...

list.add(rightClick);
list.add(leftClick);
list.add(middleClick);

由于 ? 通配符,你将无法在编译时知道实际的类型,所以:

Event<?> event = list.get(0); // 未知的确切类型

你所知道的关于 ? 就是它至少是 extends ActionType,所以你将能够使用由 ActionType 提供的所有方法,但不能使用仅在 RightClick 中引入的方法。这将需要一个显式的转换(由 instanceof 检查保护),尽管如果你必须在那里使用特定于右键单击的内容,我会对你的设计产生疑问。

英文:

Explanation

Generics are invariant. A List<Event<ActionType>> will not accept Event<RightClick>, only Event<ActionType>.

Understand generics and adjust your generic type restrictions.

If generics would be covariant, then you could give someone who expects a List<Animal> a List<Dog> and then add Cats to it. Which would cause heap corruption as dogs.get(0) could suddenly be a Cat.

An example:

List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog());

List<Animal> animals = dogs; // pretend this would work
animals.add(new Cat()); // would be legit

Dog dog = dogs.get(1); // should be safe, but is cat, heap corruption

A List<Animal> explicitly says that this list must accept all animals, also cats. But a List<Dog> is restricted to dogs only. The two lists behave differently, they have different restrictions, hence you can not use one for another. Unlike a Dog who is an Animal, a List<Dog> is not an List<Animal>, that is what is meant by co- and invariance.


Solution

The correct tool to "accept any ActionType, I do not care" are wildcards. So either go with

 List<Event<? extends ActionType>>

or just

List<Event<?>>

since the Event class already specifies the T extends ActionType restriction.

With that type you will be able to add all sorts of Events to it:

Event<RightClick> rightClick = ...
Event<LeftClick> leftClick = ...
Event<MiddleClick> middleClick = ...

list.add(rightClick);
list.add(leftClick);
list.add(middleClick);

As a consequence of the ? wildcard you will not be able to know the actual type at compile-time anymore, so:

Event<?> event = list.get(0); // unknown which exact type

All you know of ? is that it is at least extends ActionType, so you will be able to use all sorts of methods that are given by ActionType, but nothing introduced only in RightClick for example. That would require an explicit cast (guarded by an instanceof check), although I would question your design if you have to use right-click specific things there.

huangapple
  • 本文由 发表于 2020年5月2日 19:14:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/61558454.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定