2012-05-01 2 views
4

Я обычно разработчик C#, новый для Java, и я пытаюсь настроить код с помощью Generics. Мой Демонстрационный код выглядит следующим образом:Невозможно преобразовать X в T, хотя X должен соответствовать T?

// Main.java 
public static void main(String[] args) { 
    MyBase my = getMeStuff(); 
    System.out.println(my.getSomething()); 
} 

private static <T extends MyBase> T getMeStuff(){ 
    return new MyDerived(123); 
} 

// MyBase/MyDerived.java 
public class MyBase { 
    private final int something; 

    protected MyBase(int something) { this.something = something; } 

    public int getSomething() { return something; } 
} 

public class MyDerived extends MyBase { 
    public MyDerived(int something) { super(something); } 
} 

Это не может скомпилировать:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
Type mismatch: cannot convert from x.MyDerived to T 

at x.Main.getMeStuff(Main.java:14) 
at x.Main.main(Main.java:9) 

Как уже говорилось, я обычно C# Developer, поэтому код выглядит хорошо на первый взгляд. Я могу «разрешить» эту ошибку, изменив getMeStuff, чтобы добавить приведение к (T), но действительно ли это необходимо? Это немного пахнет, как будто я что-то забыл?

+4

Зачем использовать общий тип, если вы возвращаете фиксированный известный тип? –

+0

@Oli, потому что фактическая реализация более сложна и может возвращать один из многих типов (он фактически принимает класс , который создается через отражение) –

ответ

5

Проблема заключается в том, что возвращаемый тип может быть чем-то, что происходит от MyBase, и вы специально набрали его в MyDerived, который даже не работает на C# без трансляции. Вызывающий мог бы указать SomeOtherDerived вместо этого, который также происходит из MyBase, но не имеет ничего общего с MyDerived.

public class MyBase{} 
public class MyDerived extends MyBase{} 
public class SomeOtherDerived extends MyBase{} 
public static <T extends MyBase> T getAnything(){ return (T)new MyDerived(); } 

public static void main(String[] args) { 
    SomeOtherDerived instance = getAnything(); //This is legal and bad 
} 

Важно также отметить, что, даже с броском, это очень плохо и может легко привести к возникновению исключительных ситуаций во время выполнения при вызове с любым типом, который явно не представленной. Это также противоречит концепции дженериков, прибивая очень специфические типы в том, что должно быть обобщенной ситуацией.

1

Java Generics хочет помочь вам достичь безопасности типов.

Позвольте мне использовать параллельно: Давайте предположим, что вы написали <T extends MyUIControl> и в какой-то момент вы используете MyButton S с ним и где-то еще MyPanel S - которые не могут быть отлиты безопасно.

Компилятор распознал такую ​​ситуацию в коде.

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