【问题标题】:casting a Collection of derived Java interfaces (generics) [duplicate]铸造派生Java接口(泛型)的集合[重复]
【发布时间】:2014-07-13 12:02:12
【问题描述】:

制作一个供内部使用的API,我需要一些Java抽象,我不知道该怎么做。

  • 有一个接口 A 带有派生接口。
  • 假设 A 的扩展接口之一称为 B
  • 假设有一个实现 B 的类 C

我有一个工厂/池类 F,我想从中获取实例列表(或集合或类似集合)。 我想要的基本上是这样的:

List<B> instances = F.getAllSuitableInstances(parameters);

获取我的参数指定的所有实例作为 B 的集合。

第一次尝试是使用这个函数签名

public List&lt;A&gt; getAllSuitableInstances(parameters);

但是当我尝试将生成的列表转换为列表以供使用时,我 被告知“不兼容的类型”——即使 B 是从 A 派生的。

所以我尝试了 java 库的作用:

public &lt;T&gt; List&lt;T&gt; getAllSuitableInstances(parameters, T);

并尝试使用 B 作为第二个参数来调用它。但这不起作用 或者,因为出于某种原因必须将 T 作为实例提供,并且 接口不能有实例。

我知道我可以使用 &lt;?&gt; 进行强制转换,但我想让它尽可能类型安全。

那么,完成这项工作的(最佳)方法是什么?

【问题讨论】:

  • 你是对的 - 上面提到的问题的答案也回答了我的问题。但是我没有找到其他问题,因为我没有寻找它的关键字(狗,动物,多态)。也许其他人会像我一样表达他们的搜索,所以这个问题的存在可能仍然对某人有用。

标签: java generics collections interface casting


【解决方案1】:

即使 B 派生自 A。

这里你必须小心——Java的泛型是不变的,这意味着Something&lt;Superclass&gt;不是Something&lt;Subclass&gt;的超类(例如List&lt;Number&gt;不是 List&lt;Integer&gt; 的超类)。关于这个有很多问题,所以我不会重复其他人可以更有效地解释的信息,比如herehere

至于您的第二个签名,在我看来(parameters, T) 中的T 是不必要的。

public <T> List<T> getAllSuitableInstance(parameters);

应该可以,除非我误解了您的要求。这样做的缺点是T 可以是anything,所以你可以在T 类型的对象上调用的方法有些限制,但如果你不这样做,那么就没有值得关注。

如果你的接口中的方法是让你的方法工作所必需的(看起来不像,但以防万一),你总是可以为你的泛型类型添加边界(例如public &lt;T extends A&gt; List&lt;T&gt;...),所以编译器知道你的方法中所有T 的实例都是A 类型或A 的子类型。

如果您需要在方法中使用T类型(比如instanceof 检查),一个选项是传入Class 对象并使用其方法执行运行时相当于 instanceof 检查和强制转换(以及其他选项):

public <T> List<T> getAllSuitableInstance(parameters, Class<? extends T> clazz); // Might be able to use just Class<T> too

希望这会有所帮助。如果我对您的需求有什么误解,请告诉我。

【讨论】:

  • 就是这样,谢谢 - 带有 边界的版本给了我一些类型安全,同时允许所需的灵活性。您的链接为这个答案增加了价值,使其对其他读者也更有用,所以这就是我更喜欢(并接受)这个答案的原因。
  • @foo 没问题!只是一个(可能是多余的)注释——带有&lt;T extends A&gt; 的版本主要对你在inside方法中所做的工作有用。如果你只使用普通的T,我相信编译器能够找出T -&gt; B,但是在方法内部做你的工作可能会有点棘手,因为你完全不知道T 是什么(除非它是您的参数之一的一部分,例如在带有 Class 参数的版本中)。
【解决方案2】:

在使用泛型编程时,这是一个常见的误解,但它是一个重要的概念,需要学习

当我们有AB这两个具体类型时(例如NumberInteger),MyClass&lt;A&gt;MyClass&lt;B&gt;没有关系,不管A和@ 987654328@相关。

MyClass&lt;A&gt; and MyClass&lt;B&gt; is Object 的共同父母。

甚至不需要像您在第二个选项中提到的那样通过课程

这应该适合你

public <T> List<T> getAllSuitableInstances(parameters) {
List<T> list = new ArrayList<>();
 //content add to list
    return list;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-18
    • 2023-04-05
    • 2011-09-19
    相关资源
    最近更新 更多