问题
I was reading Effective Java chapter 5 about generics, in particular the items on preferring generic methods. I noticed that sometimes the type parameter(between angle brackets) in the method declaration before the return type is sometimes omitted. There are many cases like that, but for example on page 135 of the second edition:
public void popAll(Collection<E> dst) {
while (!isEmpty())
dst.add(pop());
}
On the other hand, I have seen similar generic methods with the declaration
public <E> void ...
Is the first one a typo? If not when can I omit the brackets from the declaration?
Thanks
回答1:
E
is a type variable -- it stands in for some other type, like String
or Integer
. So just as you can't understand dst.add(pop())
without knowing where and how dst
was defined, you can't understand a method declaration like popAll(Collection<E> dst)
without knowing where and how the type variable E
is defined. In the case of popAll
, the type variable E
is defined at the class level: Stack<E>
: it's the type of the elements in the stack. You'll often even see it javadoc'd:
/**A Stack of elements
*
*@param E The type of elements in the stack */
public class Stack<E>{
public void popAll(Collection<E> dst){ ... }
}
On the other hand, when you see a method declaration like public <E> void ...
, the type variable E
is being declared (not referenced from some enclosing scope like the enclosing class). In fact most times when you see a method with its own type variable, it's a static method, so there is no enclosing instance of the class to establish the value of E
.
In both cases, what is the E
type variable doing? It's telling us how two different types have to relate to each other. In popAll
, it's telling us that the element type of the collection you want to put the popped elements into has to match the element type of the stack you're popping them from.
Similarly, take the example from page 136:
public class ListUtils{
public static <E> E reduce(List<E> list, Function<E> f, E initVal);
}
Here, the E
type variable tells us that the element type of list
has to match the argument type of f
and the type of initVal
. The surrounding class does not define E
for us, it's only meaningful in the scope of the reduce
method declaration.
回答2:
The difference is that in the first case the whole class is declared generic whereas in the second case only the method is generic.
回答3:
The answer is... it's not. A "generic method" is defined to be one that declares type variables before the return type:
A method is generic if it declares one or more type variables. (JLS 8.4.4)
Therefore, popAll
is not a "generic method".
Since the method does not declare the type parameter E
, it must be defined in an enclosing scope; almost certainly by the class (a "generic class") that contains the method.
来源:https://stackoverflow.com/questions/25585581/why-are-the-angle-brackets-before-the-return-type-omitted-sometimes-from-the-def