2013-04-16 4 views
2

Пример:Непонимание класса возвращаемого экземпляра из общего метода класса вызывается из экземпляра подкласса в Java

interface S {} 

interface SS extends S {} 

abstract class A<T extends S> { 
    T get() {…} 
} 

abstract class B<BT extends SS> extends A<BT> {} 

Почему ((B)someInstanceOfB).get() возвращает объект типа S (и мы должны привести его к SS вручную), когда компилятор может определить, что возвращаемый объект по крайней мере относится к типу SS?

Почему компилятор не делает неявный класс, чтобы иметь более четкий код? Код имеет версию 1.5+, и это не секрет для компилятора. (Раскрыты)

Update: Почему не компилятор компилировать B класс, как он неявно имеет метод BT get() { return super.get(); }?

Является ли эта проблема решена в Java 1.7+?

+0

Непонятный вопрос. Но здесь 'S' и' SS' являются интерфейсами. – midhunhk

+0

@silverback пересмотренный вопрос. В чем проблема с интерфейсами? –

ответ

4

Ключом к B вы используете a raw type.

Использование исходного типа удаляет всю общую информацию от объекта, независимо от его местонахождения.

Это означает, что для исходного типа Bget метода выглядит как он возвращает S (потому что это стирание (то есть фактический типа, используемый во время выполнения) параметра типа T).

Чтобы избежать этого, никогда не использовать необработанные типы! Они предназначены исключительно для обратной совместимости и взаимодействия с устаревшим кодом.

Вместо этого B<? extends SS>.

И нет: эта проблема, вероятно, никогда не будет «решена» в любой будущей версии Java, поскольку она не существует при правильном использовании генериков.

об обновлении: нет, B делает не есть способ BT get(). Он имеет способ T get(), где T связан с параметром типа BT, который имеет нижнюю границу SS. Но так как вся информация о родовом типе отбрасывается при использовании необработанного типа, T будет еще возвращается к первоначальному стиранию, которое равно S.

правило довольно просто и в основном говорит: «Когда вы используете сырой тип, он действует так, как будто у класса вообще нет дженериков». Однако последствия не всегда очевидны, как в этом случае.

+0

Я тебя понимаю. Это сделано для обратной совместимости скомпилированных классов: иметь возможность использовать скомпилированный код новых версий с устаревшим кодом и компиляторами. –

+0

Вопрос обновлен –

+0

Некоторые мысли об обновлении вопроса. Это был риторический вопрос. Я понимаю, что до тех пор, пока логика компилятора, предложенная мной, не будет реализована (определена стандартом) в компиляторе 1.5v, она никогда не будет реализована. Что касается меня, наберите 'B 'развращает эстетику кода, и я предпочел еще несколько байтов в скомпилированном классе (неявный метод, предложенный мной). –

1

Вы не указали параметры вашего экземпляра B.

Допустим, у вас есть класс C реализующий SS:

Тогда new B<C>().get(); будет возвращать объект типа C.

На линии new B().get(); ваша IDE должна была сообщить вам «B является необработанным типом. Ссылки на общий тип B должны быть параметризованы»..

+0

Извините, я допустил ошибку ... Я обновил вопрос. –

+1

@Errandir Проблема остается прежней: используя '(B) someInstanceOfB', вы не параметризуете' B'. Вы должны использовать '(B ) someInstanceOfB', или' (B ) someInstanceOfB' по крайней мере ('get' затем вернет' Object'). – sp00m

+0

В вашей аргументации что-то не так. Кодовые куски 'S s = ((B) someInstanceOfB) .get()' и 'S s = ((A) someInstanceOfA) .get()' будет работать нормально. –

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