ChatGPT解决这个技术问题 Extra ChatGPT

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

I come across Java code like this:

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?


J
Jon Skeet

Well there's no difference between the first two - they're just using different names for the type parameter (E or T).

The third isn't a valid declaration - ? is used as a wildcard which is used when providing a type argument, e.g. List<?> foo = ... means that foo refers to a list of some type, but we don't know what.

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:

Java Tutorial on Generics

Language guide to generics

Generics in the Java programming language

Angelika Langer's Java Generics FAQ (massive and comprehensive; more for reference though)


It looks like the link to the PDF is broken. I've found what appears to be a copy here, but I can't be 100% certain since I don't know what the original looked like.
@John: Yup, that's the one. Will edit a link in, whether that one or an Oracle one...
Is there anything other than T, E and ? used in generics? If so what are they and what does they mean?
@sofs1: There's nothing special about T and E - they're just identifiers. You could write KeyValuePair<K, V> for example. ? has special meaning though.
@JonSkeet "they're just identifiers", which means they must follow the same name constraints as class names, field names, method names, etc. E.g. Foo<hello_world> is valid. Using a single upper-case letter is a naming standard, which is recommended in the Java Language Specification: "Type variable names should be pithy (single character if possible) yet evocative, and should not include lower case letters. This makes it easy to distinguish type parameters from ordinary classes and interfaces."
r
ratchet freak

It's more convention than anything else.

T is meant to be a Type

E is meant to be an Element (List: a list of Elements)

K is Key (in a Map)

V is Value (as a return value or mapped value)

They are fully interchangeable (conflicts in the same declaration notwithstanding).


The letter between the < > is just a name. What you describe in your answer are just conventions. It doesn't even have to be a single, upper-case letter; you can use any name that you like, just like you can give classes, variables etc. any name you like.
A more detailed and clear description is available in this article oracle.com/technetwork/articles/java/…
You didn't explain to the question mark. Downvoted.
Why is this even answer, anyway?
H
Hawkeye Parker

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.

First, just to be clear: the wildcard and type parameters are not the same. Where type parameters define a sort of variable (e.g., 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. Without any bounding (extends or super), the wildcard means "use any type here".

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 (e.g., T) which you can use elsewhere in the scope; the wildcard doesn't. Otherwise, there are two big differences between type params and the wildcard:

Type params can have multiple bounding classes; 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> defines Integer as a lower bound on the wildcard, meaning that the List type must be Integer or a super-type of 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. E.g. with:

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

You can pass a List<Integer>, List<Float>, List<Byte>, etc. for 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 (e.g., List<Object>), and elem must be Number or any subtype. With all the bounding, the compiler can be certain that the .add() is typesafe.


"public void foo(List numbers) {...}" should "extends" be "super" ?
No. The point of that example is to show a signature which polymorphically supports a List of Number and the sub-types of Number. For this, you use "extends". I.e., "pass me a List of Number or anything that extends Number" (List, List, whatever). A method like this might then iterate through the list and, for each element, "e", execute, e.g., e.floatValue(). Doesn't matter what sub-type (extension) of Number you pass -- you'll always be able to ".floatValue()", because .floatValue() is a method of Number.
On your last example, "List" could simply be "List" since the method does not allow anything more generic.
This answer is very very good in explaining the differences between wildcards and type parameters, there should be one dedicated question with this answer. I am going more deep in generics lately and this answer helped me a lot in putting things together, many precise infos in short, thanks !
This is the only answer that actually answers the question
P
Peter Mortensen

A type variable, , can be any non-primitive type you specify: any class type, any interface type, any array type, or even another type variable.

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

In Java 7 it is permitted to instantiate like this:

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

W
Waqas Ahmed

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


T
Tiina

compiler will make a capture for each wildcard (e.g., question mark in List) when it makes up a function like:

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>void foo(List<V> list) {
    list.put(list.get())
}