Can someone explain the declaration of these java generic methods?
I'm reading "Generics in the Java Programming Language" by Gilad Bracha and I'm confused about a style of declaration. The following code is found on page 8:
interface Collection<E>
{
public开发者_开发技巧 boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E> c);
}
interface Collection<E>
{
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
// hey, type variables can have bounds too!
}
My point of confusion comes from the second declaration. It's not clear to me what the purpose the <T>
declaration serves in the following line:
public <T> boolean containsAll(Collection<T> c);
The method already has a type (boolean) associated with it.
Why would you use the <T>
and what does it tell the complier?
I think my question needs to be a bit more specific.
Why would you write:
public <T> boolean containsAll(Collection<T> c);
vs
public boolean containsAll(Collection<T> c);
It's not clear to me, what the purpose of <T>
is, in the first declaration of containsAll.
As far as I can tell, in this case <T>
doesn't provide anything useful at all. It creates a method that is completely functionally equivalent to those using the wildcard instead.
Here are a couple of examples where it would be useful:
public List<?> transform(List<?> in);
//vs
public <T> List<T> transform(List<T> in);
In the above, you can correlate the return type with the input type. The first example cannot correlate the runtime type of the two wildcards.
public void add(List<?> list, Object obj);
//vs
public <T> void add(List<? super T> list, T obj);
In the above, the first method won't even be able to add obj
to list
since it can't be deemed to be type safe. The generic parameter in the second ensures that list
can hold whatever type obj
is.
The method already has a type (boolean) associated with it.
That is the return type. The full type of the method is “method that takes a Collection<T>
(for some T
) parameter and returns a boolean
”.
And this is where T
comes in: the parameter of the function uses it. In other words, this method can be called with different types as argument. The only restriction of these types is that they must implement the Collection<T>
interface, which itself relies on a generic argument T
(the type of the objects stored in the collection).
The ? is simply a wildcard. It means that the method will accept a Collection of any type.
The <T>
is a type parameter for the method. It is essentially assigning the wildcard a name which can then be referred to elsewhere in the method declaration and definition.
A better illustration of the difference would be if the return type of the method varied based on the type that was passed in.
Say you started with a method like
Object getRandomElement( Collection<?> c )
This will accept any Collection, but there's no way to constrain its return type. So a caller would have to cast the result back to whatever type it expected -- which should work, but raises unsafe type-conversion warnings.
With a type parameter you would instead write
<T> T getRandomElement( Collection<T> c )
In this case, if you call this method with a Collection<String>
, the compiler knows that it will return a String
.
<T>
as used here (in method declaration, before return type) is a generic type declaration. You can define new generic type for use within a method: http://download.oracle.com/javase/tutorial/java/generics/genmethods.html
Try compiling it without the <T>
.
Basically, it's telling the compiler that this method contains a generic. It isn't required in the first example because ? is a special case, and the second method is referencing the type defined in the Interface itself.
On an unrelated note, public is not required in an Interface. Methods in an interface are public by default, so can save you a bit of typing.
It declares the generic type T
used by the method. While the generic type E
is the same for the whole interface T
is limited to the method it is declared for.
精彩评论