3

Say I've an interface "Generic" -

public interface Generic<T> {
    public T echo(T input); 
    public List<String> hello();    
}

And an implementation class say GenericImpl with any trivial implementation. Now, when I create an instance of Generic and invoke hello, it returns me a List and not a List<String> -

 Generic g1 = new GenericImpl();
 for (String msg : g1.hello()) {  // Gives compilation error : 
  // Type mismatch, cannot convert from element type Object to String
 ...

Even in eclipse, when I hover on g1.hello, it shows me the return type as List and not List<String>.

This does not happen if I use a normal interface (without generic <T> ). Any suggestions on how to make it work / why does it happen ?

2 Answers2

3

You have to define the interface as generic (with a type).

Generic<YourGenericType> g1 = new GenericImpl();

By ommitting the generic definition, it will be considered a "raw type". Raw types will return Objects instead. More information on raw types can be found here.

public class Test {
    public static void main(String[] args) {
        Generic<Integer> obj = new GenericImpl();
        System.out.println(obj.echo(5));
        for(String s : obj.hello()){
            System.out.println(s);
        }
    }
}

interface Generic<T> {
    public T echo(T input); 
    public List<String> hello();    
}

class GenericImpl implements Generic<Integer> {
    @Override
    public Integer echo(Integer input) {
        return input;
    }

    @Override
    public List<String> hello() {
        return new ArrayList<String>(Arrays.asList("lala", "lolo"));
    }   
}

Output:

5
lala
lolo

Jeroen Vannevel
  • 43,651
  • 22
  • 107
  • 170
  • Ah I see. However, in my original code, I'm using a List generics, and then calling the hello method on each of them. i.e. - for (Generic generic : generics) { for (String msg : generic.hello()) { etc. So this is still a problem – Kapil Malik Dec 10 '13 at 02:17
  • Your code literally states `Generic g1 = new GenericImpl();`. Your object is defined as a raw type of `Generic`. You have to turn it into a generic type, using the generic definition. – Jeroen Vannevel Dec 10 '13 at 02:18
3

This has to do with raw types. First, a definition

To facilitate interfacing with non-generic legacy code, it is possible to use as a type the erasure (§4.6) of a parameterized type (§4.5) or the erasure of an array type (§10.1) whose element type is a parameterized type. Such a type is called a raw type.

You are using such a raw type here

Generic g1 = new GenericImpl();

since Generic has no type argument. Then the JLS also states

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.

Therefore, when using the raw type Generic, the hello() method has a return type of List which is the erasure of List<String>. As such, the return type of List#iterator() is Iterator and the return type of Iterator#next() is Object, a type which cannot be converted to String.

You will need to use a type argument for your g1's type declaration so that it is not considered a variable of a raw type.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724