5

I faced with code, which compilation result was surprised for me.

public class Test3{
    public static<K,V> Map<K,V> map(){return new HashMap<K,V>();}
}



class A{

    static void f(Map<String,Integer> bcMap){}

    public static void main(String[] args){
        f(Test3.map()) //not valid
        Map<String,Integer> m = Test3.map();//valid

    }
}

Always I supposed that if I pass value to method it means that method argument assigns to passed value.

Is it wrong ratification?

gstackoverflow
  • 36,709
  • 117
  • 359
  • 710

1 Answers1

10

Correction:

Your use of Test3.map() doesn't provide type arguments and there is no way for the compiler to infer the type arguments. The JLS says the following when failing to infer type arguments

Any remaining type variable T that has not yet been inferred is then inferred to have type Object.

So the method invocation looks like

Map<Object, Object> object = Test3.map(); 
f(object); //not valid

which is confirmed by what the error message from the compiler says:

incompatible types: java.util.Map<java.lang.Object,java.lang.Object> cannot be converted to java.util.Map<java.lang.String,java.lang.Integer>

the generic type arguments default to Object.

You can fix it by specifying the type arguments

f(Test3.<String, Integer>map()); // valid
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
  • 3
    Not sure I agree. There's no raw type used here. To me, it's just that the compiler can infer the generic types of the method based on the type of the map in the second case, but it can't in the first case, because that hasn't been implemented in the compiler. – JB Nizet Mar 16 '14 at 15:10
  • @JBNizet So it's not raw, it's just not inferrable? – Sotirios Delimanolis Mar 16 '14 at 15:10
  • That's what I would say, yes. – JB Nizet Mar 16 '14 at 15:12
  • @JB Nize If you write full answer it will very interesting for me – gstackoverflow Mar 16 '14 at 15:12
  • @gstackoverflow: I don't know what I could say in my answer that I haven't said in my comment :) – JB Nizet Mar 16 '14 at 15:13
  • @Sotirios: You probably mean `Map object = Test3.map()` – JB Nizet Mar 16 '14 at 15:15
  • @JBNizet I'm uncertain how to [interpret the JLS](http://docs.oracle.com/javase/specs/jls/se7/html/jls-15.html#jls-15.12.2.8). Is it the `Otherwise` or the line before it? I've wiki'ed the post. Make any changes you want. I need help on this one. – Sotirios Delimanolis Mar 16 '14 at 15:16
  • The compiler error message says: *incompatible types: java.util.Map cannot be converted to java.util.Map*. So the not inferred type of the argument is `Map`, not Object. – JB Nizet Mar 16 '14 at 15:20
  • @JBNizet No, that's fine, the return type is `Map`. But to determine that, it's `under the assumption that the method result was assigned to a variable of type Object.`, so the type argument is inferred to be `Object`. – Sotirios Delimanolis Mar 16 '14 at 15:21
  • 1
    @SotiriosDelimanolis: I'm not among the 10 people on earth able to understand this part of the spec (not without trying for hours at least) :-) – JB Nizet Mar 16 '14 at 15:28