Different behaviour for generic method return value to method and to assignment
Asked Answered
G

1

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?

Godsend answered 16/3, 2014 at 15:5 Comment(3)
This will be fixed in Java 8 FYI.Healey
Actually, JDK 8 is coming out this Tuesday. Seriously.Schertz
This works on Java 8. Also the return new HashMap<K,V>(); need not use the generic type arguments.Ambidexter
S
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
Selfsuggestion answered 16/3, 2014 at 15:5 Comment(10)
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.Kindly
@JBNizet So it's not raw, it's just not inferrable?Selfsuggestion
That's what I would say, yes.Kindly
@JB Nize If you write full answer it will very interesting for meGodsend
@gstackoverflow: I don't know what I could say in my answer that I haven't said in my comment :)Kindly
@Sotirios: You probably mean Map<Object, Object> object = Test3.map()Kindly
@JBNizet I'm uncertain how to interpret the JLS. 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.Selfsuggestion
The compiler error message 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>. So the not inferred type of the argument is Map<java.lang.Object,java.lang.Object>, not Object.Kindly
@JBNizet No, that's fine, the return type is Map<Object, Object>. 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.Selfsuggestion
@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) :-)Kindly

© 2022 - 2024 — McMap. All rights reserved.