2014-01-25 6 views
5

Позвольте мне показать мой быстрый пример:Неправильный общий тип возвращаемого

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 
    }       
}        

Когда данный сырьевой тип, crate.get() возвращает Food вместо Fruit

  • примечание: Crate объявлен как Crate<T extends Fruit> extends Container<T> так Crate<Food> запрещено ,

Мне просто интересно: почему метод T get() не возвращается Fruit? Почему требуется Crate<Fruit>?

+1

Вы не можете сделать 'Crate ', потому что вы заявили, что 'Crate '. «Продовольствие» не распространяется на «Фрукты». – Radiodef

+0

Ну, это очевидно. Просто смотрит на меня, поскольку компилятор не знает, чего он хочет. Сказать, что 'crate' является' Crate 'и не является одновременно – TomatoMato

+0

@TomatoMato Пожалуйста, объясните свой вопрос немного ясно. До сих пор я не понял, каков ваш вопрос на самом деле? –

ответ

5

Это происходит потому, что get объявляется Container. При использовании сырого типа Crate, который имеет эффект применения erasure ко всем его (наследуется) методов, подпись public T get() стирается с public Food get(), потому что T имеет верхнюю грань Foodв объявлении класса.

В то время как Crate сужает верхнюю границу T, которая является обратным типом get, она не отменяет этот метод. Если бы это было так, вы бы увидели другое поведение:

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 
} 

Теперь public T get() стирается в public Fruit get(), так как он был повторно объявлен в классе, где T имеет верхнюю границу Fruit.

Смежные вопросы