泛型类型和通配符类型之间的区别

时间:2022-09-01 22:55:58

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

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

function 1:

功能1:

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

}

function 2:

功能2:

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

}

Thanks.

谢谢。

7 个解决方案

#1


32  

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

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

  • 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).

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

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 <?延伸T>。例如,考虑一个方法List merge(List <?extends T>,List <?extends T>),它将两个输入列表合并到一个新的结果列表中。当然你可以引入另外两个类型参数,但你为什么要这样做?它将过度指定事物。

  • finally wildcards can have lower bounds, so with lists you can make the add method work, while get doesn'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

#2


6  

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 No way to check what was the content during the runtime.

List :E这里是Type参数,可以用来确定列表的内容类型,但没有办法检查运行时的内容是什么。

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中的,用于处理Type Parameter的问题。 “?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 accept Dog or Tiger as its content but Animal.

所以使用“public void go(ArrayList a)”不会接受Dog或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采用Dog和Tiger类型。

Check for references in Head First Java.

检查Head First Java中的引用。

#3


1  

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.

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

#4


1  

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

List作为参数类型表示参数必须是具有任何对象类型的项列表。此外,您可以绑定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之外没有办法声明对列表中项目的引用。其他帖子提供了额外的细微差别。

#5


1  

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

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

  • corresponds to "forall E, ..."
  • 对应于“forall E,......”
  • corresponds to "there exists something(denoted by ) such that ...."
  • 对应于“存在某种东西(表示为)......”

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) {

}

#6


0  

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

(自编辑以来)这两个函数签名对外部代码具有相同的效果 - 它们都将任何List作为参数。通配符等效于仅使用一次的类型参数。

#7


0  

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>

(ClassName is the name of the class containing the methods.)

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

#1


32  

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

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

  • 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).

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

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 <?延伸T>。例如,考虑一个方法List merge(List <?extends T>,List <?extends T>),它将两个输入列表合并到一个新的结果列表中。当然你可以引入另外两个类型参数,但你为什么要这样做?它将过度指定事物。

  • finally wildcards can have lower bounds, so with lists you can make the add method work, while get doesn'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

#2


6  

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 No way to check what was the content during the runtime.

List :E这里是Type参数,可以用来确定列表的内容类型,但没有办法检查运行时的内容是什么。

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中的,用于处理Type Parameter的问题。 “?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 accept Dog or Tiger as its content but Animal.

所以使用“public void go(ArrayList a)”不会接受Dog或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采用Dog和Tiger类型。

Check for references in Head First Java.

检查Head First Java中的引用。

#3


1  

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.

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

#4


1  

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

List作为参数类型表示参数必须是具有任何对象类型的项列表。此外,您可以绑定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之外没有办法声明对列表中项目的引用。其他帖子提供了额外的细微差别。

#5


1  

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

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

  • corresponds to "forall E, ..."
  • 对应于“forall E,......”
  • corresponds to "there exists something(denoted by ) such that ...."
  • 对应于“存在某种东西(表示为)......”

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) {

}

#6


0  

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

(自编辑以来)这两个函数签名对外部代码具有相同的效果 - 它们都将任何List作为参数。通配符等效于仅使用一次的类型参数。

#7


0  

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>

(ClassName is the name of the class containing the methods.)

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