简体   繁体   English

“E”、“T”和“?”有什么区别? 对于 Java generics?

[英]What is the difference between 'E', 'T', and '?' for Java generics?

I come across Java code like this:我遇到这样的 Java 代码:

public interface Foo<E> {}

public interface Bar<T> {}

public interface Zar<?> {}

What is the difference among all three of the above and what do they call this type of class or interface declarations in Java?以上三者之间有什么区别,他们将这种类型的 class 或 Java 中的接口声明称为什么?

Well there's no difference between the first two - they're just using different names for the type parameter ( E or T ). 那么前两者之间没有区别 - 他们只是为类型参数ET )使用不同的名称。

The third isn't a valid declaration - ? 第三个不是有效的声明 - ? is used as a wildcard which is used when providing a type argument , eg List<?> foo = ... means that foo refers to a list of some type, but we don't know what. 用作提供类型参数时使用的通配符 ,例如List<?> foo = ...表示foo引用某种类型的列表,但我们不知道是什么。

All of this is generics , which is a pretty huge topic. 所有这些都是泛型 ,这是一个非常大的话题。 You may wish to learn about it through the following resources, although there are more available of course: 您可能希望通过以下资源了解它,尽管当然有更多可用的资源:

It's more convention than anything else. 它比其他任何东西都更常见。

  • T is meant to be a Type T意味着是一种类型
  • E is meant to be an Element ( List<E> : a list of Elements) E意味着是一个元素( List<E> :元素列表)
  • K is Key (in a Map<K,V> ) K是Key(在Map<K,V>
  • V is Value (as a return value or mapped value) V是值(作为返回值或映射值)

They are fully interchangeable (conflicts in the same declaration notwithstanding). 它们完全可以互换(尽管存在相同声明中的冲突)。

The previous answers explain type parameters (T, E, etc.), but don't explain the wildcard, "?", or the differences between them, so I'll address that. 前面的答案解释了类型参数(T,E等),但不解释通配符,“?”或它们之间的差异,所以我将解决这个问题。

First, just to be clear: the wildcard and type parameters are not the same. 首先,要明确:通配符和类型参数不一样。 Where type parameters define a sort of variable (eg, T) that represents the type for a scope, the wildcard does not: the wildcard just defines a set of allowable types that you can use for a generic type. 其中类型参数定义了一种表示范围类型的变量(例如,T),通配符不是:通配符只定义了一组可用于泛型类型的允许类型。 Without any bounding ( extends or super ), the wildcard means "use any type here". 没有任何边界( extendssuper ),通配符意味着“在这里使用任何类型”。

The wildcard always come between angle brackets, and it only has meaning in the context of a generic type: 通配符总是位于尖括号之间,它只在泛型类型的上下文中有意义:

public void foo(List<?> listOfAnyType) {...}  // pass a List of any type

never 决不

public <?> ? bar(? someType) {...}  // error. Must use type params here

or 要么

public class MyGeneric ? {      // error
    public ? getFoo() { ... }   // error
    ...
}

It gets more confusing where they overlap. 它们重叠的地方会变得更加混乱。 For example: 例如:

List<T> fooList;  // A list which will be of type T, when T is chosen.
                  // Requires T was defined above in this scope
List<?> barList;  // A list of some type, decided elsewhere. You can do
                  // this anywhere, no T required.

There's a lot of overlap in what's possible with method definitions. 方法定义可能存在很多重叠。 The following are, functionally, identical: 以下是功能相同的:

public <T> void foo(List<T> listOfT) {...}
public void bar(List<?> listOfSomething)  {...}

So, if there's overlap, why use one or the other? 那么,如果有重叠,为什么要使用其中一个呢? Sometimes, it's honestly just style: some people say that if you don't need a type param, you should use a wildcard just to make the code simpler/more readable. 有时,它实际上只是风格:有人说如果你不需要类型参数,你应该使用通配符来使代码更简单/更易读。 One main difference I explained above: type params define a type variable (eg, T) which you can use elsewhere in the scope; 我在上面解释了一个主要区别:type params定义了一个类型变量(例如,T),你可以在范围的其他地方使用它; the wildcard doesn't. 通配符没有。 Otherwise, there are two big differences between type params and the wildcard: 否则,类型参数和通配符之间有两个很大的区别:

Type params can have multiple bounding classes; 类型params可以有多个边界类; the wildcard cannot: 通配符不能:

public class Foo <T extends Comparable<T> & Cloneable> {...}

The wildcard can have lower bounds; 通配符可以有下限; type params cannot: 类型参数不能:

public void bar(List<? super Integer> list) {...}

In the above the List<? super Integer> 在上面的List<? super Integer> List<? super Integer> defines Integer as a lower bound on the wildcard, meaning that the List type must be Integer or a super-type of Integer. List<? super Integer>Integer定义为通配符的下限,这意味着List类型必须是Integer或Integer的超类型。 Generic type bounding is beyond what I want to cover in detail. 泛型类型边界超出了我想要详细介绍的范围。 In short, it allows you to define which types a generic type can be. 简而言之,它允许你定义一个泛型类型可以是类型 This makes it possible to treat generics polymorphically. 这使得可以多态地处理泛型。 Eg with: 例如:

public void foo(List<? extends Number> numbers) {...}

You can pass a List<Integer> , List<Float> , List<Byte> , etc. for numbers . 你可以通过一个List<Integer> List<Float>List<Byte>等,为numbers Without type bounding, this won't work -- that's just how generics are. 没有类型边界,这将无法工作 - 这就是泛型。

Finally, here's a method definition which uses the wildcard to do something that I don't think you can do any other way: 最后,这是一个方法定义,它使用通配符做一些我认为你不能做任何其他方式的事情:

public static <T extends Number> void adder(T elem, List<? super Number> numberSuper) {
    numberSuper.add(elem);
}

numberSuper can be a List of Number or any supertype of Number (eg, List<Object> ), and elem must be Number or any subtype. numberSuper可以是Number of Number或任何超类型的Number(例如, List<Object> ), elem必须是Number或任何子类型。 With all the bounding, the compiler can be certain that the .add() is typesafe. 通过所有边界,编译器可以确定.add()是类型安全的。

A type variable, <T>, can be any non-primitive type you specify: any class type, any interface type, any array type, or even another type variable. 类型变量<T>可以是您指定的任何非基本类型:任何类类型,任何接口类型,任何数组类型,甚至是其他类型变量。

The most commonly used type parameter names are: 最常用的类型参数名称是:

  • E - Element (used extensively by the Java Collections Framework) E - Element(Java Collections Framework广泛使用)
  • K - Key K - 钥匙
  • N - Number N - 数字
  • T - Type T型
  • V - Value V - 价值

In Java 7 it is permitted to instantiate like this: 在Java 7中,允许实例化如下:

Foo<String, Integer> foo = new Foo<>(); // Java 7
Foo<String, Integer> foo = new Foo<String, Integer>(); // Java 6

The most commonly used type parameter names are: 最常用的类型参数名称是:

E - Element (used extensively by the Java Collections Framework)
K - Key
N - Number
T - Type
V - Value
S,U,V etc. - 2nd, 3rd, 4th types

You'll see these names used throughout the Java SE API 您将在整个Java SE API中看到这些名称

compiler will make a capture for each wildcard (eg, question mark in List) when it makes up a function like: 当编译一个函数时,编译器将对每个通配符 (例如,List中的问号)进行捕获

foo(List<?> list) {
    list.put(list.get()) // ERROR: capture and Object are not identical type.
}

However a generic type like V would be ok and making it a generic method : 但是像V这样的泛型类型可以使它成为通用方法

<V>void foo(List<V> list) {
    list.put(list.get())
}

<?> means “any”. <?>表示“任何”。

<T> means “specific type”. <T>表示“特定类型”。

<E> means "element" and is commonly used in the Java Collections Framework. <E>表示“元素”,常用于 Java Collections 框架中。

Suppose we have two classes:假设我们有两个类:

   public class DataType<E>{
    private E data;
    private DataType<E> next;
// constructor, getters, setters, toString();

} }

and

public class LinkedListDemo{
public static void main(String[] args){
DataType<Integer> type1 = new DataType<Integer>(5, null);
DataType<Number> type2 = new DataType<>(Double.valueOf(23.4), null);
type2.setNext(type2);
}

In the second class, the line type2.setNext(type2) won't work because for the type1 we have <Integer> as a parametrized type and for the type2 we have <Number> as a parametrized type.在第二个 class 中,行type2.setNext(type2)将不起作用,因为对于 type1,我们将<Integer>作为参数化类型,对于 type2,我们将<Number>作为参数化类型。 From the point of view of <E> it's impossible.<E>的角度来看,这是不可能的。

But when we write in this line question mark <?> :但是当我们在这一行写问号<?>

private DataType<?> next; 

This error disappears.此错误消失。 With question mark <?> it can be of any type.带有问号<?>它可以是任何类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM