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

Java:有界通配符或有界类型参数?

吕博耘
2023-03-14
问题内容

最近,我读了这篇文章:http
:
//download.oracle.com/javase/tutorial/extra/generics/wildcards.html

我的问题是,而不是创建像这样的方法

public void drawAll(List<? extends Shape> shapes){
    for (Shape s: shapes) {
        s.draw(this);
    }
}

我可以创建一个这样的方法,它可以正常工作:

public <T extends Shape> void drawAll(List<T> shapes){
    for (Shape s: shapes) {
        s.draw(this);
    }
}

我应该使用哪种方式?通配符在这种情况下有用吗?


问题答案:

这取决于您 需要 做什么。如果要执行以下操作,则需要使用bounded type参数:

public <T extends Shape> void addIfPretty(List<T> shapes, T shape) {
    if (shape.isPretty()) {
       shapes.add(shape);
    }
}

在这里我们有一个List<T> shapes和一个T shape,因此我们可以放心shapes.add(shape)。如果已声明List<? extends Shape>,则 不能 安全地add使用它(因为您可能有List<Square>Circle)。

因此,通过给有界类型参数命名,我们可以选择在通用方法的其他地方使用它。当然,并非总是需要此信息,因此,如果您不需要太多有关类型的信息(例如your
drawAll),那么仅使用通配符就足够了。

即使您不再引用边界类型参数,如果您有多个边界,仍然需要边界类型参数。这是Angelika
Langer的Java泛型常见问题解答中的报价

通配符绑定和类型参数绑定有什么区别?

通配符只能有一个界限,而类型参数可以有多个界限。通配符可以有一个下限或上限,而类型参数没有下限。

通配符界限和类型参数界限经常被混淆,因为它们既称为界限,又具有部分相似的语法。[…]

语法

  type parameter bound     T extends Class & Interface1 & … & InterfaceN

  wildcard bound  
      upper bound          ? extends SuperType
      lower bound          ? super   SubType

通配符只能有一个界限,即下限或上限。不允许使用通配符范围列表。

相反,类型参数可以有多个界限,但是没有类型参数的下界。

从行情 有效的Java第二版,第28项:使用界通配符来增加灵活性API

为了获得最大的灵活性,请在代表生产者或消费者的输入参数上使用通配符类型。[…] PECS代表生产者- extends,消费者- super[…]

不要将通配符类型用作返回类型
。与其给用户提供更多的灵活性,不如说是迫使他们在客户端代码中使用通配符类型。正确使用的通配符类型对于类的用户几乎是不可见的。它们使方法接受应接受的参数,并拒绝应拒绝的参数。
如果类的用户必须考虑通配符类型,则类的API可能存在问题

应用PECS原理,我们现在可以返回addIfPretty示例,并通过编写以下代码使其更加灵活:

public <T extends Shape> void addIfPretty(List<? super T> list, T shape) { … }

现在我们可以addIfPretty说a Circle到a List<Object>。这显然是类型安全的,但是我们的原始声明不够灵活,无法允许它。

相关问题

  • Java泛型:什么是PECS?
  • 有人可以解释什么<? super T>意思,什么时候应使用它,以及该构造应如何与<T>and 配合使用<? extends T>

摘要

  • 一定要使用有界类型参数/通配符,它​​们会增加API的灵活性
  • 如果类型需要多个参数,则别无选择,只能使用有界类型参数
  • 如果类型需要下限,则别无选择,只能使用有界通配符
  • “生产者”具有较高的界限,“消费者”具有较低的界限
  • 不要在返回类型中使用通配符


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

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

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

  • 问题内容: 摘自Effective Java Chapter 5(泛型): 这两个声明中的哪一个是可取的,为什么?在公共API中,第二个更好,因为它更简单。您传入一个列表(任何列表),该方法交换索引元素。没有类型参数值得担心。通常,如果类型参数在方法声明中仅出现一次,则将其替换为通配符。 我不明白,为什么第二个选项对我的API客户端来说更简单?我可以将相同的参数传递给第一个和第二个方法。第二种方法

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

  • 问题内容: 我在很多地方都读过,包括在方法返回类型中使用有界通配符是一个坏主意。但是,我在课堂上找不到避免这种情况的方法。我想念什么吗? 情况看起来像这样: 总而言之,这是一个我希望能够 使用 任何与英语有所不同的出版物的类。该类需要允许从外部访问发布,但理想情况下,的调用者不希望将结果用作有界通配符。他们会很高兴的。 有办法解决吗? 问题答案: 有界通配符具有传染性,这就是您链接到的页面似乎在哀