当前位置: 首页 > 面试题库 >

为什么在有界通配符泛型中不能有多个接口?

高寒
2023-03-14
问题内容

我知道Java的泛型类型有各种各样的违反直觉的属性。特别是我不理解的一个,希望有人可以向我解释。为类或接口指定类型参数时,可以对其进行绑定,以使其必须使用来实现多个接口public class Foo<T extends InterfaceA & InterfaceB>。但是,如果要实例化实际对象,则此方法不再起作用。List<? extends InterfaceA>很好,但是List<? extends InterfaceA & InterfaceB>无法编译。考虑以下完整代码段:

import java.util.List;

public class Test {

  static interface A {
    public int getSomething();
  }

  static interface B {
    public int getSomethingElse();
  }

  static class AandB implements A, B {
    public int getSomething() { return 1; }
    public int getSomethingElse() { return 2; }
  }

  // Notice the multiple bounds here. This works.
  static class AandBList<T extends A & B> {
    List<T> list;

    public List<T> getList() { return list; }
  }

  public static void main(String [] args) {
    AandBList<AandB> foo = new AandBList<AandB>(); // This works fine!
    foo.getList().add(new AandB());
    List<? extends A> bar = new LinkedList<AandB>(); // This is fine too
    // This last one fails to compile!
    List<? extends A & B> foobar = new LinkedList<AandB>();
  }
}

似乎bar应该明确定义的语义-我想通过允许两种类型(而不只是一种类型)的交集,不会损失类型安全性。我敢肯定有一个解释。有谁知道它是什么?


问题答案:

有趣的是,接口java.lang.reflect.WildcardType看起来支持通配符arg的上限和下限。每个都可以包含多个边界

Type[] getUpperBounds();
Type[] getLowerBounds();

这超出了语言所允许的范围。源代码中有一个隐藏的注释

// one or many? Up to language spec; currently only one, but this API
// allows for generalization.

该界面的作者似乎认为这是偶然的限制。

您问题的罐头答案是,泛型本身已经太复杂了;增加更多的复杂性可能被证明是最后一根稻草。

为了使通配符具有多个上限,必须通读规范并确保整个系统仍然有效。

我知道的一个麻烦是类型推断。当前的推理规则根本无法处理交集类型。没有减少约束的规则A&B << C。如果我们减少到

    A<<C 
  or
    A<<B

当前任何推理引擎都必须进行大修,以允许这种分歧。但是真正的严重问题是,这允许有多种解决方案,但是没有理由偏爱一个解决方案。

但是,推断对于类型安全性不是必不可少的。在这种情况下,我们可以简单地拒绝推断,并要求程序员显式填充类型参数。因此,推理的难度并不是反对干涉类型的有力依据。



 类似资料:
  • 根据Joshua Bloch的“有效Java”一书,关于如何/何时在泛型中使用有界通配符有一个规则。这个规则就是PECS(productor-extends,Comsumer-Super)。当我研究以下示例时: 根据PECS规则,上述声明是错误的。但是我希望有一个的,并向这个传递一个。为什么不做呢? 为什么要始终使用关键字?为什么使用是错误的? 当然,这也代表了Comsumer的观点。为什么消费者

  • 我正在与Java8通配符泛型作斗争。 假设一个名为的泛型类(来自Core Java book) 是因为Java8编译器转换吗?超级经理反对,因此任何事情都是允许的?

  • 问题内容: 下列类定义了两种方法,它们在直观上都具有相同的功能。每个函数都有两个类型和一个布尔值的列表来调用,该值指定应将这些列表中的哪个分配给局部变量。 根据,有效而无效。它抱怨: 我知道查找包含三元运算符()的表达式类型的规则非常复杂,但是据我了解,它选择了最具体的类型,第二个和第三个参数都可以转换为该类型,而无需显式投。在这里,应该是,但不是。 我想解释一下为什么不是这种情况,最好参考 Ja

  • 在了解Java泛型的过程中,我遇到了以下问题: 假设我有下面的方法来添加列表的元素,只限于包含数字的列表。 但是这段代码和这段代码有什么不同: 它们都按预期编译和执行。这两者之间有什么区别?除了语法之外?什么时候我更喜欢使用通配符而不是前者? 是的,使用通配符方法,我不能在列表中添加除null之外的新元素,否则它将无法编译。除此之外呢?

  • null 编译,我真的不明白为什么。基本上与第1行相同的问题。是的超类,如何将超类的成员放入此中? 编译。与第1行相同的问题。

  • 问题内容: 我想拥有一个Class对象,但是我想强迫它代表的任何类扩展A类并实现接口B。 我可以: 要么: 但我不能两者都做。有没有办法做到这一点? 问题答案: 实际上,你可以做你想做的事。如果要提供多个接口或一个类加接口,则必须使通配符看起来像这样: 请参见sun.com上的泛型教程,特别是页面底部的“ 绑定类型参数”部分。实际上,如果需要,你可以列出多个接口,并& InterfaceName根