Отличие состоит в том, что Some<E extends Some>
означает две вещи:
E
является сырым типом. Вкратце, типы raw имеют всю общую информацию, удаляемую из класса, что, в свою очередь, может создать неожиданное поведение E
, может быть любым классом Some
! Наоборот, использование Some<E extends Some<E>>
означает:
E
напечатан E
должен быть тем же как класс, в котором он объявлен Необработанная часть - проблема, но большая импликация - это границы типов. Этот код демонстрирует разницу, поскольку классы «B» используют (или пытаются использовать) классы «A» как общий тип.
// The raw version
interface Some<E extends Some> {
E get();
}
class SomeA implements Some<SomeA> {
public SomeA get() {
return new SomeA();
}
}
// Compiles OK
class SomeB implements Some<SomeA> {
public SomeA get() {
return new SomeA();
}
}
// The typed version
interface SomeT<E extends SomeT<E>> {
E get();
}
class SomeTA implements Some<SomeTA> {
public SomeTA get() {
return new SomeTA();
}
}
// Compile error
class SomeTB implements SomeT<SomeA> {
public SomeA get() {
return new SomeTA();
}
}
Класс SomeB
компилирует в порядке - тип E привязан только к Some
, поэтому будет выполняться любой класс Some
, но класс SomeTB
выдает ошибку компиляции:
аргумент типа SomeTA не входит в число границы переменной типа E
blockquote>Тип
E
должен быть точно таким же, как содержащий класс.Это важно, если вы ожидаете параметров и возвращаемые типы должны быть такими же, как и сам класс, который обычно вы хотите использовать с типизированными классами.
Тип, ограниченный сырым типом, не является проблемой, поскольку он все еще является
Some
, но могут быть случаи, когда это имеет значение (я не могу думать об этом только сейчас).