Are Java Generics an All or Nothing Decision?

I have the following code:

public class Main {
    public static void main(String[] args) {
        Generic generic = new Generic<Integer>(5);
        List<String> stringList = generic.getStringList(); // this line is where the compiler complains
    }
}

public class Generic<T> {
    private T member;

    public Generic(T member) {
        this.member = member;
    }

    public T getMember() {
        return member;
    }

    public List<String> getStringList() {
        return new ArrayList<String>();
    }
}

Note that class Generic is declared with a generic type parameter, but the variable generic in method main is of the erasure type, i. e. without a type parameter. What I do not understand is why the compiler complains about the line with the assignment of the List<String>:

Warning:(6, 56) java: unchecked conversion
  required: java.util.List<java.lang.String>
  found:    java.util.List

The Method clearly returns a List<String>, independently of the generic parameter of the class. And this is what the variable stringList expects. It seems that not using the generic parameter on class level for variable generic switches off all generics processing, and not just that depending on the type parameter of the class.

I am using the standard Oracle Java 1.7.0_55 compiler, if that matters.

I am not asking how to get rid of the warning. I know I should declare the variable type as Generic<Integer>, or could use @SuppressWarnings("unchecked"). My questions are the following:

Is this behavior documented?

What is the reason for this strange behavior?

Jon Skeet
people
quotationmark

When you use the erasure of a type, it removes all trace of generics - not just the uses of the type parameter T. So your generic variable acts as if it's referring to this type:

// After type erasure
public class Generic {
    private Object member;

    public Generic(Object member) {
        this.member = member;
    }

    public Object getMember() {
        return member;
    }

    public List getStringList() {
        return new ArrayList();
    }
}

This is documented in the JLS - start at section 4.6 and follow the links. It's not as clear as it might be, but it is documented.

The reasoning is that if you're using a raw type, the compiler expects you to not be aware of generics at all - because it's likely to be compiling legacy pre-Java-5 code. That's proved a little unrealistic over time, but I believe it was the motivation for the spec being the way it is.

people

See more on this question at Stackoverflow