java 泛型类型和通配符类型的区别

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10943137/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 03:10:16  来源:igfitidea点击:

Difference between generic type and wildcard type

javagenericswildcard

提问by Fio

I'm a newbie in Generic and my question is: what difference between two functions:

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

function 1:

功能一:

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

}

function 2:

功能二:

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

}

采纳答案by Jens Schauder

The first signature says: list1 is a List of Es.

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

The second signature says: list is a List of instances of some type, but we don't know the type.

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

The difference becomes obvious when we try to change the method so it takes a second argument, which should be added to the list inside the method:

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

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
    }
}

The first one works nicely. And you can't change the second argument into anything that will actually compile.

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

Actually I just found an even nicer demonstration of the difference:

实际上,我刚刚找到了一个更好的差异演示:

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 !!!!!!!!!
    }
}

One might as why do we need <?>when it only restricts what we can do with it (as @Babu_Reddy_H did in the comments). I see the following benefits of the wildcard version:

人们可能会问为什么我们需要<?>它,因为它只限制了我们可以用它做什么(就像@Babu_Reddy_H 在评论中所做的那样)。我看到通配符版本的以下好处:

  • The caller has to know less about the object he passes in. For example if I have a Map of Lists: Map<String, List<?>>I can pass its values to your function without specifying the type of the list elements. So

  • If I hand out objects parameterized like this I actively limit what people know about these objects and what they can do with it (as long as they stay away from unsafe casting).

  • 调用者不必知道他传入的对象。例如,如果我有一个列表映射:Map<String, List<?>>我可以将它的值传递给您的函数,而无需指定列表元素的类型。所以

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

These two make sense when I combine them: List<? extends T>. For example consider a method List<T> merge(List<? extends T>, List<? extends T>), which merges the two input lists to a new result list. Sure you could introduce two more type parameters, but why would you want to? It would be over specifying things.

当我将它们合并这两个是有意义的:List<? extends T>。例如,考虑一个方法List<T> merge(List<? extends T>, List<? extends T>),它将两个输入列表合并为一个新的结果列表。当然你可以再引入两个类型参数,但你为什么要这么做?这将结束指定的事情。

  • finally wildcards can have lower bounds, so with lists you can make the addmethod work, while getdoesn't give you anything useful. Of course that triggers the next question: why don't generics have lower bounds?
  • 最后通配符可以有下限,因此使用列表可以使add方法起作用,get而不会给您任何有用的东西。这当然会引发下一个问题:为什么泛型没有下界?

For a more in depth answer see: When to use generic methods and when to use wild-card?and http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203

有关更深入的答案,请参阅:何时使用泛型方法以及何时使用通配符?http://www.angelikalanger.com/GenericsFAQ/FAQSections/TypeArguments.html#FAQ203

回答by Kumar Vivek Mitra

Generics makes the collection more type safe.

泛型使集合类型更安全。

List<E>: E here is the Type Parameter, which can be used to determine the content type of the list, but there was Noway to check what was the content during the runtime.

List<E>:E 这里是Type Parameter,可以用来判断列表的内容类型,但是Noruntime.

Generics are checked only during compilation time.

<? extends String>: This was specially build into java, to handle the problem which was with the Type Parameter. "? extends String"means this List can have

<? extends String>:这是专门内置到java中的,用于处理类型参数的问题。"? extends String"意味着这个 List 可以有

objects which IS-A String.

For eg:

例如:

Animal class Dog class extends Animal Tiger class extends Animal

动物类狗类扩展动物老虎类扩展动物

So using "public void go(ArrayList<Animal> a)"will NOT acceptDog or Tiger as its content but Animal.

所以使用 "public void go(ArrayList<Animal> a)"will NOT acceptDog 或 Tiger 作为其内容,但使用 Animal。

"public void go(ArrayList<? extends Animal> a)"is whats needed to make the ArrayList take in Dog and Tiger type.

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

Check for references in Head First Java.

检查 Head First Java 中的引用。

回答by user3509406

I usually explain the difference between <E> and <?> by a comparison with logical quantifications, that is, universal quantification and existential quantification.

我通常会解释 < E> 和 < ? > 通过与逻辑量化的比较,即全称量化和存在量化。

  • corresponds to "forall E, ..."
  • corresponds to "there exists something(denoted by ) such that ...."
  • 对应于“forall E, ...”
  • 对应于“存在某物(由 表示)使得......”

Therefore, the following generic method declaration means that, for all class type E, we define funct1

因此,以下泛型方法声明意味着,对于所有类类型E,我们定义funct1

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

}

The following generic method declaration means that, for some existing class denoted by <?>, we define funct2.

以下泛型方法声明意味着,对于由 < 表示的某些现有类>,我们定义funct2.

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

}

回答by Pramod Kumar

The first is a function that accepts a parameter that must be a list of items of E type.

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

the second example type is not defined

未定义第二个示例类型

List<?> list

so you can pass list of any type of objects.

所以你可以传递任何类型的对象的列表。

回答by Gene

List as a parameter type says that the parameter must be a list of items with any object type. Moreover, you can bind the Eparameter to declare references to list items inside the function body.

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

The List as a parameter type has the same semantics, except that there is no way to declare references to the items in the list other than to use Object. Other posts give additional subtle differences.

作为参数类型的 List 具有相同的语义,除了使用Object. 其他帖子给出了额外的细微差别。

回答by newacct

(Since your edit) Those two function signatures have the same effect to outside code -- they both take any Listas argument. A wildcard is equivalent to a type parameter that is used only once.

(由于您的编辑)这两个函数签名对外部代码具有相同的效果——它们都将 anyList作为参数。通配符相当于只使用一次的类型参数。

回答by fabian

In addition to those differences mentioned before, there is also an additional difference: You can explicitly set the type arguments for the call of the generic method:

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

List<Apple> apples = ...
ClassName.<Banana>funct2(apples); // for some reason the compiler seems to be ok
                               // with type parameters, even though the method has none

ClassName.<Banana>funct1(apples); // compiler error: incompatible types: List<Apple>
                                  //                 cannot be converted to List<Banana>

(ClassNameis the name of the class containing the methods.)

ClassName是包含方法的类的名称。)