为了账号安全,请及时绑定邮箱和手机立即绑定

何时使用通用方法,何时使用通配符?

何时使用通用方法,何时使用通配符?

潇湘沐 2019-07-06 14:29:05
何时使用通用方法,何时使用通配符?我正在阅读关于泛型方法的文章。OracleDocGenericMethod..当它说明何时使用通配符和何时使用泛型方法时,我对这种比较感到非常困惑。引用文件中的话。interface Collection<E> {     public boolean containsAll(Collection<?> c);     public boolean addAll(Collection<? extends E> c);}我们本可以在这里使用通用方法,而不是:interface Collection<E> {     public <T> boolean containsAll(Collection<T> c);     public <T extends E> boolean addAll(Collection<T> c);     // Hey, type variables can have bounds too!}[…]这告诉我们,类型参数用于多态性;它的唯一效果是允许在不同的调用站点上使用各种实际的参数类型。如果是这样的话,应该使用通配符。通配符是为了支持灵活的子类型而设计的,这正是我们在这里试图表达的。我们不觉得不像(Collection<? extends E> c);是否也支持某种多态性?那么,为什么在这种情况下泛型方法的使用被认为是不好的呢?继续向前,它说,泛型方法允许使用类型参数来表示方法和/或其返回类型的一个或多个参数类型之间的依赖关系。如果不存在这种依赖关系,则不应该使用泛型方法。这是什么意思?他们给出了这个例子class Collections {     public static <T> void copy(List<T> dest, List<? extends T> src) {     ...}[…]我们可以用另一种方式编写此方法的签名,而无需使用通配符:class Collections {     public static <T, S extends T> void copy(List<T> dest, List<S> src) {     ...}文档阻止第二个声明并促进第一个语法的使用?第一次声明和第二次声明有什么区别?两人似乎都在做同样的事?有人能给这个地区开个灯吗。
查看完整描述

3 回答

?
HUWWW

TA贡献1874条经验 获得超12个赞

在某些地方,通配符和类型参数会做同样的事情。但也有一些地方,您必须使用类型参数。

  1. 如果要对不同类型的方法参数强制执行某种关系,则不能使用通配符,必须使用类型参数。

以您的方法为例,假设您希望确保srcdest传递给copy()方法应该是相同的参数化类型,您可以使用类型参数这样做:

public static <T extends Number> void copy(List<T> dest, List<T> src)

在这里,你可以确保destsrc具有相同的参数化类型List..所以,可以安全地从srcdest.

但是,如果您继续更改方法以使用通配符:

public static void copy(List<? extends Number> dest, List<? extends Number> src)

它不会像预期的那样起作用。在第二种情况下,你可以通过List<Integer>List<Float>destsrc..因此,将元素从srcdest不会再安全了。如果您不需要这样的关系,那么您可以完全不使用类型参数。

使用通配符和类型参数之间的其他区别是:

  • 如果只有一个参数化类型参数,则可以使用通配符,尽管类型参数也会工作。
  • 类型参数支持多个边界,通配符不支持。
  • 通配符支持上下界,类型参数只支持上界。因此,如果您想要定义一个采用List类型Integer或者是超级班,你可以:

    public void print(List<? super Integer> list)  // OK

    但是不能使用类型参数:

     public <T super Integer> void print(List<T> list)  // Won't compile

参考资料:


查看完整回答
反对 回复 2019-07-06
?
四季花海

TA贡献1811条经验 获得超5个赞

考虑以下由JamesGosling第4版编写的Java编程示例,在下面我们要合并2 SinglyLinkQueue:

public static <T1, T2 extends T1> void merge(SinglyLinkQueue<T1> d, SinglyLinkQueue<T2> s){
    // merge s element into d}public static <T> void merge(SinglyLinkQueue<T> d, SinglyLinkQueue<? extends T> s){
        // merge s element into d}

上述两种方法都具有相同的功能。那么哪个更好呢?答案是第二。用作者自己的话说:

“一般规则是在可能时使用通配符,因为通配符代码通常比具有多个类型参数的代码更具可读性。在决定是否需要类型变量时,问问自己该类型变量是否用于关联两个或多个参数,还是将参数类型与返回类型相关联。如果答案是否定的,那么通配符就足够了。”

注意:书中只给出了第二种方法,类型参数名为S而不是‘T’。第一种方法不在书中。


查看完整回答
反对 回复 2019-07-06
?
冉冉说

TA贡献1877条经验 获得超1个赞

在第一个问题中:这意味着如果参数的类型与方法的返回类型之间存在关系,那么使用泛型。

例如:

public <T> T giveMeMaximum(Collection<T> items);public <T> Collection<T> applyFilter(Collection<T> items);

在这里,您将按照一定的标准提取一些T。如果T是Long您的方法将返回LongCollection<Long>实际返回类型取决于参数类型,因此使用泛型类型是有用的,并建议使用泛型类型。

如果不是这种情况,可以使用通配符类型:

public int count(Collection<?> items);public boolean containsDuplicate(Collection<?> items);

在这两个示例中,无论集合中的项的类型是什么,返回类型都是intboolean.

在你们的例子中:

interface Collection<E> {
    public boolean containsAll(Collection<?> c);
    public boolean addAll(Collection<? extends E> c);}

这两个函数将返回一个布尔值,不管集合中项的类型如何。在第二种情况下,它仅限于E.

第二个问题:

class Collections {
    public static <T> void copy(List<T> dest, List<? extends T> src) {
    ...}

这第一段代码允许您传递一个异构代码。List<? extends T> src作为参数。这个列表可以包含不同类的多个元素,只要它们都扩展了基类T。

如果你有:

interface Fruit{}

class Apple implements Fruit{}class Pear implements Fruit{}class Tomato implements Fruit{}

你可以

List<? extends Fruit> basket = new ArrayList<? extends Fruit>();basket.add(new Apple());basket.add(new Pear());
basket.add(new Tomato());List<Fruit> fridge = new ArrayList<Fruit>(); Collections.copy(fridge, basket);// works

另一方面

class Collections {
    public static <T, S extends T> void copy(List<T> dest, List<S> src) {
    ...}

约束List<S> src作为一个特殊的类S,它是T的一个子类,列表只能包含一个类的元素(在本例中是S),而不能包含其他类的元素,即使它们也实现了T。您将无法使用我前面的示例,但您可以这样做:

List<Apple> basket = new ArrayList<Apple>();basket.add(new Apple());basket.add(new Apple());basket.add(new Apple());
List<Fruit> fridge = new ArrayList<Fruit>();Collections.copy(fridge, basket);
/* works since the basket is defined as a List of apples and not a list of some fruits. */


查看完整回答
反对 回复 2019-07-06
  • 3 回答
  • 0 关注
  • 492 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号