Java wildcards behave strangely when classes are generic

I think I have some good understanding of Java generics

This code is not compiled. I know why

We can only pass the type of test method type animal or its supertype (such as object list)

package scjp.examples.generics.wildcards;

import java.util.ArrayList;
import java.util.List;

class Animal {}
class Mammal extends Animal {}
class Dog extends Mammal {}

public class Test {

    public void test(List<? super Animal> col) {
        col.add(new Animal());
        col.add(new Mammal());
        col.add(new Dog());
    }

    public static void main(String[] args) {
        List<Animal> animalList = new ArrayList<Animal>();
        List<Mammal> mammalList = new ArrayList<Mammal>();
        List<Dog> dogList = new ArrayList<Dog>();

        new test().test(animalList);
        new test().test(mammalList); // Error: The method test(List<? super Animal>) in the type Test is not applicable for the arguments (List<Mammal>)  
        new test().test(dogList);    // Error: The method test(List<? super Animal>) in the type Test is not applicable for the arguments (List<Dog>)

        Dog dog = dogList.get(0);
    }        
}

But there is a strange part here (at least for me)

If we declare that the class test is generic by adding only < T >, it will compile! And throw Java lang.ClassCastException:

public class Test<T> {
...
}

,

Exception in thread "main" java.lang.ClassCastException: scjp.examples.generics.wildcards.Animal cannot be cast to scjp.examples.generics.wildcards.Dog

My question is why adding a generic class type < T > (which is not used anywhere) causes class compilation and changes wildcard behavior?

Solution

The expression new test() is of primitive type The member types of the original type of Java language specification definitions are as follows:

Deletion of list is a list

The rationale behind this definition may be that primitive types are intended as a means of using generic types from non generic legacy code, where type parameters never exist They are not designed, are not optimal, and do not specify type parameters; This is the purpose of wildcard type, that is, if you write a compiler compliance level greater than 1.5, you should write

Test<?> test = maketest();
    test.test(animalList);
    test.test(mammalList);
    test.test(dogList);

Rejoice (or curse, for that matter) when a compilation error is found again

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>