Java – Tricky Java Generics : generic class implementing non generic interface with generic Method

genericsjava

I have the following code as seen in ideone.com:

import java.util.*;

class Test{
   interface Visitor{
        public <T> void visit(T Value);
   }

   class MyVisitor<T> implements Visitor{
        List<T> list = new  ArrayList<T>();

        public <T> void visit(T value){
           list.add(value);
        }
    }
}

When compiled this code will produce the following+ error:

 Main.java:12: error: no suitable method found for add(T#1)
             list.add(value);
                 ^
     method List.add(int,T#2) is not applicable
       (actual and formal argument lists differ in length)
     method List.add(T#2) is not applicable
       (actual argument T#1 cannot be converted to T#2 by method invocation conversion)   where T#1,T#2 are type-variables:
     T#1 extends Object declared in method visit(T#1)
     T#2 extends Object declared in class Test.MyVisitor 1 error

The problem is that the type T in visit is not considered the same T in list . How can I fix this compilation problem?

Best Answer

class MyVisitor<T> implements Visitor{
    List<T> list = new  ArrayList<T>();

    public <T> void visit(T value){
       list.add(value);
    }
}

is equivalent to

class MyVisitor<T> implements Visitor{
    List<T> list = new  ArrayList<T>();

    public <V> void visit(V value){
       list.add(value);
    }
}

i.e. the T parameter to the class and the T parameter to the visit method are not related, and neither is necessarily assignable to the other. If Visitor were itself a parameterized interface

interface Visitor<V>{
    public void visit(V Value);
}

then you could have MyVisitor<T> implements Visitor<T> and the T's would then be the same.

Remember that the point of generic methods is to link the types of two or more parameters, or to link the type of a parameter to the return type of the method (e.g. a method that takes a parameter of some type and returns a List of the same type). When a generic method only uses its parameter once it doesn't really gain anything from being generic, i.e. you would get just as much type safety from

interface Visitor{
    public void visit(Object Value);
}

as you would from your original Visitor interface.

Related Topic