Java:有界通配符还是有界类型参数? [英] Java: bounded wildcards or bounded type parameter?

查看:34
本文介绍了Java:有界通配符还是有界类型参数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Recently, I read this article: http://download.oracle.com/javase/tutorial/extra/generics/wildcards.html

我的问题是,不要创建这样的方法:

My question is, instead of creating a method like this:

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

我可以创建一个这样的方法,而且效果很好:

I can create a method like this, and it works fine:

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

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

Which way should I use? Is wildcard useful in this case?

推荐答案

这取决于您需要做什么.如果你想做这样的事情,你需要使用有界类型参数:

It depends on what you need to do. You need to use the bounded type parameter if you wanted to do something like this:

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

这里我们有一个 Listshape 和一个 T shape,因此我们可以安全地shapes.add(shape).如果它被声明为 List,你可以NOT安全地add到它(因为你可能有一个List和一个>圈).

Here we have a List<T> shapes and a T shape, therefore we can safely shapes.add(shape). If it was declared List<? extends Shape>, you can NOT safely add to it (because you may have a List<Square> and a Circle).

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

So by giving a name to a bounded type parameter, we have the option to use it elsewhere in our generic method. This information is not always required, of course, so if you don't need to know that much about the type (e.g. your drawAll), then just wildcard is sufficient.

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

Even if you're not referring to the bounded type parameter again, a bounded type parameter is still required if you have multiple bounds. Here's a quote from Angelika Langer's Java Generics FAQs

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

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

A wildcard can have only one bound, while a type parameter can have several bounds. A wildcard can have a lower or an upper bound, while there is no such thing as a lower bound for a type parameter.

通配符边界和类型参数边界经常被混淆,因为它们都被称为边界并且有部分相似的语法.[…]

Wildcard bounds and type parameter bounds are often confused, because they are both called bounds and have in part similar syntax. […]

语法:

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

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

一个通配符只能有一个界限,下限或上限.不允许使用通配符边界列表.

A wildcard can have only one bound, either a lower or an upper bound. A list of wildcard bounds is not permitted.

相比之下,一个类型参数可以有多个边界,但没有一个类型参数的下限这样的东西.

A type parameter, in constrast, can have several bounds, but there is no such thing as a lower bound for a type parameter.

引自 Effective Java 2nd Edition,Item 28:使用有界通配符提高 API 灵活性:

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

For maximum flexibility, use wildcard types on input parameters that represent producers or consumers. […] PECS stands for producer-extends, consumer-super […]

不要使用通配符类型作为返回类型.它不会为您的用户提供额外的灵活性,而是强制他们在客户端代码中使用通配符类型.如果使用得当,通配符类型对于类的用户几乎是不可见的.它们导致方法接受他们应该接受的参数并拒绝他们应该拒绝的参数.如果类的用户必须考虑通配符类型,则类的 API 可能有问题.

Do not use wildcard types as return types. Rather than providing additional flexibility for your users, it would force them to use wildcard types in client code. Properly used, wildcard types are nearly invisible to users of a class. They cause methods to accept the parameters they should accept and reject those they should reject. If the user of the class has to think about wildcard types, there is probably something wrong with the class's API.

应用 PECS 原则,我们现在可以回到 addIfPretty 示例并通过编写以下内容使其更加灵活:

Applying the PECS principle, we can now go back to our addIfPretty example and make it more flexible by writing the following:

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

现在我们可以addIfPretty,比如说,一个Circle,到一个List.这显然是类型安全的,但我们最初的声明不够灵活,无法允许它.

Now we can addIfPretty, say, a Circle, to a List<Object>. This is obviously typesafe, and yet our original declaration was not flexible enough to allow it.

  • Java Generics: What is PECS?
  • Can someone explain what does <? super T> mean and when should it be used and how this construction should cooperate with <T> and <? extends T>?
  • 一定要使用有界类型参数/通配符,它​​们会增加 API 的灵活性
  • 如果类型需要多个参数,你别无选择,只能使用有界类型参数
  • 如果类型需要下限,您别无选择,只能使用有界通配符
  • 生产者"有上限,消费者"有下限
  • 不要在返回类型中使用通配符

这篇关于Java:有界通配符还是有界类型参数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆