Что отличалось бы в Java, если бы Перечислимое объявление не имело рекурсивной части

См. определение Перечисления Java и Почему в перечислении Java объявляется, поскольку Перечисление > для общего обсуждения. Здесь я хотел бы изучить то, что точно было бы повреждено (не безопасный с точки зрения типов больше, или требование дополнительных бросков и т.д.), если бы Класс Enum был определен как

public class Enum 

Я использую этот код для тестирования моих идей:

interface MyComparable {
    int myCompare(T o);
}

class MyEnum implements MyComparable {
    public int myCompare(E o) { return -1; }
}

class FirstEnum extends MyEnum {}

class SecondEnum extends MyEnum {}

С ним я не смог найти любые преимущества в этом точном случае.

PS. то, что мне не разрешают сделать

class ThirdEnum extends MyEnum {}

то, когда MyEnum определяется с рекурсией,
a) не релевантный, потому что с реальными перечислениями Нельзя сделать это просто, потому что Вы не можете расширить перечисление сами
b) не верный - попробуйте его в компиляторе и посмотрите, что это на самом деле может скомпилировать w/o любые ошибки

PPS. Я все более склонен полагать, что корректный ответ здесь был бы, "ничто не изменится, если Вы удалите рекурсивную часть" - но я просто не могу верить этому.

14
задан Community 23 May 2017 в 10:32
поделиться

5 ответов

Я считаю, что убедительной причиной для этого является то, что это делает код в классе 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, и эти вызовы будут безопасными для типов.

1
ответ дан 1 December 2019 в 16:44
поделиться

Рассмотрим Enum .compareTo (E other) .

Это:

  • Необходимо работать с E, а не с перечислением, чтобы вы не пытались сравнивать одно значение перечисления со значением из другого перечисления.
  • Необходимо иметь возможность получить порядковое значение перечисления с помощью метода ordinal () , объявленного в Enum .

Как бы вы предложили сделать это без текущего ограничения?

Это только первый вопрос, который я придумал ... Я уверен, что есть много других. По сути, это способ сказать: «Вы не должны пытаться рассматривать все перечисления как эквивалентные друг другу ... перечисление само по себе является закрытым набором, но все перечисления разделяют определенные свойства»

. ]
1
ответ дан 1 December 2019 в 16:44
поделиться

Если бы у вас не было параметра универсального типа, вы не смогли бы расширить 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 ) );
}

В этом случае, если вы не переопределите равным , вы потеряете соглашение о том, что x.comparesTo (y) = 0 подразумевает x.equals (y) ; если вы переопределяете равно, то есть случаи, когда x.equals (y) не подразумевает x == y (как и для других объектов значений), тогда как для Java перечисляются оба теста равенство дают тот же результат.

0
ответ дан 1 December 2019 в 16:44
поделиться

Ну, во-первых, он будет жаловаться на использование необработанного типа, но вы можете сделать:

public class Enum<E extends Enum<?>>

для того же эффекта.

Кроме того, с этим типом универсального кода вы можете сделать что-то вроде:

class FirstEnum extends MyEnum<SecondEnum> {
}

class SecondEnum extends MyEnum<FirstEnum> {
}

, что, как мне кажется, может привести к большим проблемам. Точнее, вы не можете сравнить перечисление типа FirstEnum с перечислением того же типа, вам нужно сравнить его с перечислением другого типа, что действительно проблематично, если у вас есть List , который вы хотите отсортировать. Пример не будет компилироваться, если я установлю E вместо o ? , поскольку SecondEnum не относится к типу E extends MyEnum (это приведет к циклическому наследованию ). Он будет работать, если FirstEnum расширяет MyEnum (что будет означать, что SecondEnum является дочерним классом FirstEnum - нормального иерархического наследования).

2
ответ дан 1 December 2019 в 16:44
поделиться
`X extends Enum<Y>`

было бы незаконно. это является релевантным. компилятор может иметь специальные правила с enum, но почему бы не иметь идеальное объявление типов, если это возможно?

0
ответ дан 1 December 2019 в 16:44
поделиться
Другие вопросы по тегам:

Похожие вопросы: