1

In this static function in Java, why must <K, V> be repeated in line 1?

public static <K, V> HashMap<K, V> newInstance() {
  return new HashMap<K, V>();
} 

I understand why HashMap<K, V> is necessary since the function returns a HashMap with generic types K and V as keys and values respectively. However, why is the first <K, V> necessary in the function signature?

John Hoffman
  • 15,137
  • 19
  • 50
  • 75
  • See also [*Type Inference for Generic Instance Creation*](http://docs.oracle.com/javase/7/docs/technotes/guides/language/type-inference-generic-instance-creation.html). – trashgod Jun 23 '12 at 22:17

4 Answers4

6

To indicate that the method is a generic method, using/returning generic types. If they were not there, the compiler would look for a concrete type named K, and another concrete type named V.

emory
  • 10,259
  • 1
  • 28
  • 55
JB Nizet
  • 633,450
  • 80
  • 1,108
  • 1,174
1

Because the function newInstance is generic as well, with generic types K and V which are forwarded to HashMap. Its meant to be used like this:

HashMap<Integer, String> map = newInstance<Integer,String>();
K-ballo
  • 76,488
  • 19
  • 144
  • 164
1

To add to the other answers, with erasure all the types are lost at compile time. However, the compiler checks for validation first and that is why the types are needed then.

Here is an example of what happens after erasure from another SO answer:

But when generics are used, they're converted into compile-time checks and execution-time casts. So this code:

List list = new ArrayList(); list.add("Hi"); String x = list.get(0);

is compiled into

List list = new ArrayList(); list.add("Hi"); String x = (String) list.get(0);

Community
  • 1
  • 1
James Drinkard
  • 13,634
  • 14
  • 99
  • 132
1

Could the compiler reasonably infer type parameters?

Yes in the example situation - static HashMap<K,V>newInstance(){return new HashMap<>();} is obviously short for static < K extends Object , V extends Object > HashMap<K,V>newInstance()return new HashMap<K,V>();}.

But if your compiler inferred type parameters, then your code would still compile even when you mistype class names. static void setName ( Sting name ) is probably wrong but your compiler would assume you meant <Sting extends Object> static void setName ( Sting name ); Through the magic of runtime erasure that would be equivalent to static void setName ( Object name ) ;.

If the method is not static, then inference becomes problematic. class X { HashMap<K,V>newInstance(){return new HashMap<>();}} could be type-inferred as one of the following:

  1. class X <K extends Object , V extends Object> { HashMap<K,V>newInstance(){return new HashMap<>();}}
  2. class X <K extends Object > { < V extends Object > HashMap<K,V>newInstance(){return new HashMap<>();}}
  3. class X <V extends Object> { < K extends Object > HashMap<K,V>newInstance(){return new HashMap<>();}}
  4. class X { <K extends Object , V extends Object> HashMap<K,V>newInstance(){return new HashMap<>();}}

In addition, if type parameters were inferred then what is the order. When they are explicitly stated, the order is obvious. The only (obvious to me) way to solve the order problem for inferred type parameters is the order they were declared in the code. But if you just reverse the order of 2 lines of code (which should be inconsequential) you could potentially change the public interface breaking the build. So brittle!

emory
  • 10,259
  • 1
  • 28
  • 55