简体   繁体   中英

Why calling a generic method with different types gives compilation error?

I am trying to learn java generics. I wrote a method:

public <T> T Gmethod(T a,Collection<T> list){   
        return a;}

While calling this with Gmethod("A",list); is fine where list is type of Object ,

But calling it with Gmethod(new Object(),list); where list is type of String is error, Why?

Having

<T> T method(T a, Collection<T> list) { return a; }

and calling it with

Collection<Object> list = new LinkedList<>();
method("A", list);

will cause the compiler to infer the type Object for the type variable T , as list is of type Collection<Object> . The type of variable a is String , which is a subtype of Object . So this method call is allowed.

Calling the method with

Collection<String> list = new LinkedList<>();
method(new Object(), list);

will again cause the compiler to infer the type Object for the type variable T , as now a is of type Object . So the compiler requests the argument for parameter list to be of type Collection<Object> (or a subtype). But Collection<String> is not a subtype of Collection<Object> . So the compiler does not allow this method call.

When you have a reference T the actual class can be T or a subclass. When you have a <T> it has to be that class and only that class. This is required as it is a container of a references and modifying this container can alter the original. This doesn't happen with a plain reference as it is passed as a copy.

A reference is copied by value.

String a = "hi";
Object b = a;
b = new Object(); // no problem as `a` is not changed by this.

But for containers this doesn't work so well as only the reference to the container is copied, not the container itself.

List<String> a = new ArrayList<>();
a.add("hi");
List<Object> b = (List) a; // compiler warning.
b.add(new Object());       // alters `a` in an incorrect way.
a.get(1);                  // ClassCastException oops.

As @Seelenvirtuose and @Peter Lawrey have suggested in their answer that this is because of Type Inference that compiler does for you.

To test that compiler binds the first call to Object try this,

class Main{

     public static void main(String[] args){
          Collection<Object> listOfObject = new ArrayList<>();
          Main.<String>method("a",listOfObject); //compile time error here
     }

     public static <T> T Gmethod(T a, Collection<T> coll){
        return a;
     }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM