Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiler error on Java generic interface with a List<> method [duplicate]

I don't understand the compiler error resulting from the following code. I define a generic interface, see Task, with two methods: U doSomething(String value) and List<Integer> getIDs(). The doSomething() method actually uses the generic type as the type of its return value, but doesn't seem to be causing problems. The getIDs() method returns a List, which is unrelated to the type of Task, but it is causing problems when using for..each statement to iterate over the return value. The following compiler error occurs.

error: incompatible types
    for (Integer value : task.getIDs()){
required: Integer
found:    Object

It seems that the type erasure on the interface is causing the compiler to forget the declared type on the second method, which is unrelated to the generic type. Or in other words why is the generic type on the interface affecting how the compiler understands the return value on the getIDs() method and specifically in the context of a for..each statement?

Apparently if I get reference to the list outside of the for..each there is no problem, but not directly.

public class InterfaceTest {
   public static void main(String[] args) {
      Task task = new MyTask();
      // no complaints about the type here     
      List<Integer> values = task.getIDs();

      // getting a compiler error for this line
      for (Integer value : task.getIDs()){

      }
   }
}


interface Task<U>{
   U doSomething(String value);
   List<Integer> getIDs();
}

The implementation of the interface isn't necessary to demonstrate the point, but I didn't want to leave the reference Task task = null; and have answer's telling me that's the problem.

class MyTask implements Task<Boolean>{

   @Override
   public Boolean doSomething(String value) {
      System.out.println(value);
      return false;
   }

   @Override
   public List<Integer> getIDs() {
      return Arrays.asList( 1, 2, 3, 4 );
   }
}
like image 257
Martin Woolstenhulme Avatar asked Jun 19 '13 02:06

Martin Woolstenhulme


People also ask

Why remove method is not generic in Java?

remove() (in Map as well as in Collection ) is not generic because you should be able to pass in any type of object to remove() . The object removed does not have to be the same type as the object that you pass in to remove() ; it only requires that they be equal.

CAN interface have generic in Java?

Java Generic Interface In similar way, we can create generic interfaces in java. We can also have multiple type parameters as in Map interface. Again we can provide parameterized value to a parameterized type also, for example new HashMap<String, List<String>>(); is valid.

How do you declare a generic method How do you invoke a generic method?

Generic MethodsAll generic method declarations have a type parameter section delimited by angle brackets (< and >) that precedes the method's return type ( < E > in the next example). Each type parameter section contains one or more type parameters separated by commas.


2 Answers

What is happening is when use use a class (or interface) with a generic parameter <T> but refer to and instance of the without <T> (ie. that raw type) the compiler erases all generic type information from the class. This is likely due to compatibility with pre-1.5 source code where you wouldn't be able to use generic type information at all.

Consider the situation where you are writing code and compiling on a Java 1.4 compiler. You want to use a library which makes use of generics. When you refer to a type from that library which has generic parameters as a raw type, the compiler enforces the use of no generic parameters.

EDIT:

The JLS-4.8-210 alludes to this when it mentions (credit: zhong-j-yu):

The type of a constructor (§8.8), instance method (§8.4, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

This still feels like a gotcha, but it is likely for some reason.

like image 120
Craig Avatar answered Sep 22 '22 19:09

Craig


The error seems to lie here:

Task task = new MyTask();

You have forgotten to add generics after Task. It should work if you change it to one of these:

Task<Boolean> task = new MyTask();
Task<?> task = new MyTask();
like image 42
Lone nebula Avatar answered Sep 21 '22 19:09

Lone nebula