Что было бы иначе в Java, если декларация Enum не имела рекурсивной части
См.
Определение Java Enum
а также
Почему в java перечисление объявляется как Enum < E extends Enum <E →
для общей дискуссии. Здесь я хотел бы узнать, что именно было бы сломано (не больше типов, или требует дополнительных приведений и т.д.), Если класс Enum был определен как
public class Enum<E extends Enum>
Я использую этот код для тестирования своих идей:
interface MyComparable<T> {
int myCompare(T o);
}
class MyEnum<E extends MyEnum> implements MyComparable<E> {
public int myCompare(E o) { return -1; }
}
class FirstEnum extends MyEnum<FirstEnum> {}
class SecondEnum extends MyEnum<SecondEnum> {}
С этим я не смог найти никаких преимуществ в этом конкретном случае.
PS. тот факт, что мне не разрешено делать
class ThirdEnum extends MyEnum<SecondEnum> {}
когда MyEnum определяется с рекурсией -
a) не имеет значения, потому что с реальными перечислениями вам не разрешено делать это только потому, что вы не можете расширять enum самостоятельно
b) не верно - попробуйте в компиляторе и убедитесь, что он действительно может скомпилировать без каких-либо ошибок.
ПФС. Я все больше склонен полагать, что правильный ответ здесь будет "ничего не изменится, если вы удалите рекурсивную часть", но я просто не могу в это поверить.
Ответы
Ответ 1
Я считаю, что убедительной причиной этого является то, что он делает код в классе MyEnum более типичным.
Считайте, что рекурсивная часть делает такую вещь возможной:
class MyEnum<E extends MyEnum<E>> {
private Thing<E> util1() { return someObject }
private void util2(E e) {}
public int method(E o) {
Thing<E> thingy = o.util1();
// You can call the util1 method on o and get a type safe return element.
E o1 = // I don't care how you get a parametrized E object.
o.util2(o1);
// You can call the util2 method with a typesafe parameter.
}
}
Короче говоря, эта рекурсия позволяет помещать типы типов в класс Enum, которые вы можете вызвать для любого элемента E, и эти вызовы будут типаными.
Ответ 2
Ну, в первую очередь, он будет жаловаться на использование raw-типа, но вы могли бы сделать:
public class Enum<E extends Enum<?>>
для того же эффекта.
Кроме того, с этим типом родословной вы можете сделать что-то вроде:
class FirstEnum extends MyEnum<SecondEnum> {
}
class SecondEnum extends MyEnum<FirstEnum> {
}
который мне кажется, что это может привести к большим проблемам. Точнее, вы не можете сравнить перечисление типа FirstEnum с перечислением того же типа, вы должны сравнить его с перечислением другого типа, что очень сложно, если у вас есть List<FirstEnum>
, который вы хотите отсортировать. Пример не будет компилироваться, если я установил E
вместо o ?
, поскольку SecondEnum не относится к типу E extends MyEnum<E>
(это приведет к циклическому наследованию). Он будет работать, если FirstEnum extends MyEnum<FirstEnum>
хотя (что будет означать, что SecondEnum является дочерним классом FirstEnum - нормальным иерархическим наследованием).
Ответ 3
Рассмотрим Enum<E>.compareTo(E other)
.
Что:
- Нужно работать с E, а не enum, чтобы вы не пытались сравнить одно значение enum со значением из другого перечисления
- Нужно иметь возможность получить порядковое значение перечисления с помощью метода
ordinal()
, объявленного на Enum
.
Как вы могли бы предложить эту работу без текущего ограничения?
Это только первый, с которым я пришел... Я уверен, что есть много других. В основном это способ сказать: "Вы не должны пытаться рассматривать все перечисления как эквивалентные друг другу... enum является замкнутым множеством сам по себе, но все перечисления имеют определенные свойства".
Ответ 4
Если у вас не было параметра типового типа, вы не сможете расширить Comparable<T extends Comparable>
для определенного подтипа перечисления, которое вы создали.
Вы можете проигнорировать это и создать свой собственный тип MyEnum, который будет вести себя так же, но без ограничения того, что разные MyEnum не сопоставимы:
public abstract class MyEnum implements Comparable<MyEnum>
{
private final int ordinal;
protected MyEnum ( int ordinal )
{
this.ordinal = ordinal;
}
public int ordinal ()
{
return ordinal ;
}
public int compareTo ( MyEnum other )
{
return ordinal - other.ordinal; // ignore overflow for now
}
public boolean equals (Object other) {
return ordinal == ((MyEnum)other).ordinal;
}
public int hashCode () {
return ordinal;
}
}
Это ведет себя почти так же, как перечисление для определенных операций, но вместо того, чтобы быть безопасным для универсального типа, подчиняется LSP - объекты разных подклассов MyEnum сопоставимы или равны друг другу, если они имеют одинаковое порядковое значение.
public static class EnumA extends MyEnum
{
private EnumA ( int ordinal ) { super ( ordinal ); }
public static final EnumA a = new EnumA ( 0 );
public static final EnumA b = new EnumA ( 1 );
}
public static class EnumB extends MyEnum
{
private EnumB ( int ordinal ) { super ( ordinal ); }
public static final EnumB x = new EnumB ( 0 );
public static final EnumB y = new EnumB ( 1 );
}
public static void main ( String...args )
{
System.out.println ( EnumA.a.compareTo ( EnumB.x ) );
System.out.println ( EnumA.a.equals ( EnumB.x ) );
System.out.println ( EnumA.a.compareTo ( EnumB.y ) );
System.out.println ( EnumA.a.equals ( EnumB.y ) );
}
В этом случае, если вы не переопределяете equals
, вы теряете соглашение, которое x.comparesTo(y)=0
означает x.equals(y)
; если вы переопределяете равные, тогда бывают случаи, когда x.equals(y)
не подразумевает x == y
(как для других объектов значений), тогда как для перечислений Java оба теста равенства дают один и тот же результат.
Ответ 5
`X extends Enum<Y>`
будет незаконным. это relavant. компилятор может иметь специальные правила с enum
, но почему бы не получить объявление идеального типа, если это возможно?