通用类型和通配符类型之间的差异

问题描述 投票:50回答:7

我是Generic的新手,我的问题是:两个功能之间有什么区别:

功能1:

public static <E> void funct1  (List<E> list1) {

}

功能2:

public static void funct2(List<?> list) {

}
java generics wildcard
7个回答
34
投票

第一个签名说:list1是一个ES列表。

第二个签名说:list是某种类型的实例的列表,但我们不知道类型。

当我们尝试更改方法时,区别变得明显,因此它需要第二个参数,应将其添加到方法内部的列表中:

import java.util.List;

public class Experiment {
    public static <E> void funct1(final List<E> list1, final E something) {
        list1.add(something);
    }

    public static void funct2(final List<?> list, final Object something) {
        list.add(something); // does not compile
    }
}

第一个效果很好。而且您不能将第二个参数更改为可以实际编译的任何内容。

实际上我只是发现了一个更好的区别说明:

public class Experiment {
    public static <E> void funct1(final List<E> list) {
        list.add(list.get(0));
    }

    public static void funct2(final List<?> list) {
        list.add(list.get(0)); // !!!!!!!!!!!!!! won't compile !!!!!!!!!
    }
}

[一个可能为什么我们只需要限制我们可以使用<?>的原因(就像@Babu_Reddy_H在注释中所做的那样)。我看到了通配符版本的以下好处:

  • 调用者必须对他传入的对象了解得更少。例如,如果我有一个列表列表:Map<String, List<?>>,我可以将其值传递给您的函数,而无需指定列表元素的类型。所以

  • 如果我分发像这样参数化的对象,我会积极限制人们对这些对象的了解以及它们可以做什么(只要它们远离不安全的铸造)。

当我将它们组合在一起时,这两个是有意义的:List<? extends T>。例如,考虑一种方法List<T> merge(List<? extends T>, List<? extends T>),该方法将两个输入列表合并为一个新的结果列表。当然可以引入另外两个类型参数,但是为什么要这么做呢?这将超过指定的东西。

  • 最后通配符可以有一个较低的界限,因此使用列表可以使add方法起作用,而get则没有任何用处。当然,这触发了下一个问题:为什么泛型没有下界?

有关更深入的答案,请参见:When to use generic methods and when to use wild-card?http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203


7
投票

泛型使集合的类型更加安全。

List<E>:E,这里是类型参数,可以用来确定列表的内容类型,但是有No种方法可以检查runtime期间的内容。

Generics are checked only during compilation time.

<? extends String>:这是Java专门构建的,用于处理类型参数的问题。 "? extends String"表示此列表可以具有

objects which IS-A String.

例如:

动物类狗类延伸动物老虎类延伸动物

因此,使用"public void go(ArrayList<Animal> a)"NOT accept狗或老虎作为其内容,但将其作为动物。

"public void go(ArrayList<? extends Animal> a)"是制作ArrayList take in Dog and Tiger type.所需的内容>

在Head First Java中检查引用。


1
投票

第一个是接受参数的函数,该参数必须是E类型的项目的列表。


1
投票

作为参数类型的列表表示,该参数必须是具有任何对象类型的项目的列表。此外,您可以绑定E参数来声明对函数体内列表项的引用。


1
投票

我通常通过与逻辑量化(即通用量化和存在量化)进行比较来解释<< [E] >>和<< [?] >>之间的区别。


0
投票

除了前面提到的那些差异之外,还存在其他差异:您可以为泛型方法的调用显式设置类型参数:


0
投票
([ClassName是包含方法的类的名称。)
© www.soinside.com 2019 - 2024. All rights reserved.