Why does a Java generic raw class erase all generics to object when type parameters are unspecified? [duplicate]

StackOverflow https://stackoverflow.com/questions/17743406

  •  03-06-2022
  •  | 
  •  

Pergunta

If I have a class:

public class GenericClass<TBlah extends Number> {
    public List<String> getList() {
        return null;
    }
}

When I attempt to use that method from another class:

public class OtherClass {
    public void test() {
        GenericClass a = null;
        for (String s : a.getList()) {

        }
    }
}

Why does a.getList() return a List<Object> until I change the line above the for loop to:

GenericClass<Number> a = null;

At which point a.getList() returns a List<String> like it should do?

Edit: I don't understand why the contract specified by getList() should be affected whatsoever by how I declare my variable 'a'. getList() always returns a List<String>, it doesn't matter what TBlah is.

Foi útil?

Solução

Because this is how generics work. Do not forget that before generics when you declared a List it was a list of Object. You were expected to put/get Object and you were forced to cast to get your object with the correct type. Actually it still is a list of Object in runtime.

Generics is a way for the compiler to guarentee you type safety at compile time assuming you have no warnings. In runtime there are no List<String>. There is just List. The compiler puts the automatic cast for you, so you are able in your code to write String s = list.get(i) without casting.

When you declare GenericClass a you are declaring a raw type (you should get a warning on this) thus the compiler does not have a way to know what type the a.getList() is supposed to return. So it uses Object. When you declare GenericClass<Number> a = null; now the compiler knows what type to expect for the a.getList() and uses the desired one.

Edit: It should be clarified that the compiler can know what to expect only if you respect the contract of the signature (i.e. as is the case with GenericClass<Number>). If you don't respect the contract (i.e. you are using a raw type that does not extends Number) then the contract does not apply anymore. The compiler behaves as if no type information was present. Do not forget that the compiler needs to also maintain backwards compatibility with code that was created in the pre-generics era

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top