Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Wrong generic return type

Tags:

java

generics

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

  • note: Crate is declared as Crate<T extends Fruit> extends Container<T> so Crate<Food> is forbidden.

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

like image 367
TomatoMato Avatar asked Jan 25 '14 18:01

TomatoMato


1 Answers

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.

like image 130
Paul Bellora Avatar answered Oct 29 '22 16:10

Paul Bellora