TomatoMato
TomatoMato

Reputation: 713

Wrong generic return type

Let me show my quick example:

public class Main {

    public static abstract class Food { 
    }

    public static abstract class Fruit extends Food {
        public String getJuice(){
            return "juice";
        }
    }

    public static abstract class Container<T extends Food> {
        private T food;
        public final T get(){
            return food;
        }
    }

    public static abstract class Crate<T extends Fruit> extends Container<T> {
    }

    public static void Bar(Crate crate) {
        Food  f  = crate.get(); //compiles fine
      //Fruit f2 = crate.get(); //can't compile
    }                           
}                               

When given a raw type, crate.get() returns Food instead of Fruit

I am just curious: why does the method T get() not return Fruit? Why is Crate<Fruit> required?

Upvotes: 5

Views: 156

Answers (1)

Paul Bellora
Paul Bellora

Reputation: 55213

This happens because get is declared by Container. When using the raw type Crate, which has the effect of applying erasure to all of its (inherited) methods, the signature of public T get() is erased to public Food get(), because T has an upper bound of Food in its declaring class.

While Crate narrows the upper bound of T, which happens to be the return type of get, it doesn't override that method. If that were the case, you would see different behavior:

public static abstract class Container<T extends Food> {
    private T food;
    public T get() {
        return food;
    }
}

public static abstract class Crate<T extends Fruit> extends Container<T> {

    @Override
    public T get() {
        return super.get();
    }
}

public static void bar(Crate crate) {
    Food  f  = crate.get(); // compiles fine
    Fruit f2 = crate.get(); // also compiles
}

Now, public T get() is erased to public Fruit get(), since it has been redeclared in a class where T has an upper bound of Fruit.

Upvotes: 5

Related Questions