Why are the angle brackets before the return type omitted sometimes from the definition of a generic method

♀尐吖头ヾ 提交于 2021-02-04 15:09:30

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!