如果 Enum 声明没有递归部分,Java 中会有什么不同

发布于 2024-09-06 06:57:55 字数 1032 浏览 6 评论 0 原文

请参阅 Java 枚举定义为什么在java中枚举被声明为Enum> 供一般性讨论。在这里,我想了解如果定义了 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> {}

有了它,我无法找到任何好处在这种情况下。

附言。 我不允许这样做的事实

class ThirdEnum extends MyEnum<SecondEnum> {}

当 MyEnum 用递归定义时 是
a)不相关,因为对于真正的枚举,您不能仅仅因为自己无法扩展枚举而这样做
b) 不正确 - 请在编译器中尝试一下,看看它实际上能够编译,没有任何错误

PPS。我越来越倾向于相信这里的正确答案是“如果删除递归部分,什么都不会改变”——但我就是不敢相信。

Please see
Java Enum definition
and
Why in java enum is declared as Enum<E extends Enum<E>>
for general discussion. Here I would like to learn what exactly would be broken (not typesafe anymore, or requiring additional casts etc) if Enum class was defined as

public class Enum<E extends Enum> 

I'm using this code for testing my ideas:

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> {}

With it I wasn't able to find any benefits in this exact case.

PS. the fact that I'm not allowed to do

class ThirdEnum extends MyEnum<SecondEnum> {}

when MyEnum is defined with recursion is
a) not relevant, because with real enums you are not allowed to do that just because you can't extend enum yourself
b) not true - pls try it in a compiler and see that it in fact is able to compile w/o any errors

PPS. I'm more and more inclined to believe that the correct answer here would be "nothing would change if you remove the recursive part" - but I just can't believe that.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

却一份温柔 2024-09-13 06:57:55

好吧,首先它会抱怨使用原始类型,但你可以这样做:

public class Enum<E extends Enum<?>>

以获得相同的效果。

另外,使用这种类型的泛型,您可以执行以下操作:

class FirstEnum extends MyEnum<SecondEnum> {
}

class SecondEnum extends MyEnum<FirstEnum> {
}

在我看来,这可能会导致很多麻烦。更确切地说,您不能将 FirstEnum 类型的枚举与相同类型的枚举进行比较,您必须将其与其他类型的枚举进行比较,如果您有一个 ListList 你想要排序的。如果我设置 E 而不是 ?,则该示例将无法编译,因为 SecondEnum 不是 E extends MyEnum 类型(这会导致循环继承)。如果 FirstEnum extends MyEnum 它将起作用(这意味着 SecondEnum 是 FirstEnum 的子类 - 正常的层次继承)。

Well, first of all it would complain about using the raw type, but you could do:

public class Enum<E extends Enum<?>>

for the same effect.

Also, with this type of generic you could do something like:

class FirstEnum extends MyEnum<SecondEnum> {
}

class SecondEnum extends MyEnum<FirstEnum> {
}

which to me seems like it could lead to a lot of trouble. More exactly you can't compare an enum of type FirstEnum with an enum of the same type, you have to compare it with an enum of the other type, which is really troublesome if you have a List<FirstEnum> that you want sorted. The example will not compile if i set E instead o ? since SecondEnum is not of the type E extends MyEnum<E> (this would lead to circular inheritance). It will work if FirstEnum extends MyEnum<FirstEnum> though (which would mean that SecondEnum is a child class of FirstEnum - normal hierarchical inheritance).

2024-09-13 06:57:55

我相信这样做的一个令人信服的理由是它使 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 元素上调用这些方法,并且这些调用将是类型安全的。

I believe that a compelling reason to do that is that it makes the code in the MyEnum class more typesafe.

Consider that the recursive part makes such a thing possible:

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.
    }
}

In short, that recursivity lets you put typesafe methods in the Enum class that you can call on any E element, and these calls will be typesafe.

荆棘i 2024-09-13 06:57:55

考虑Enum.compareTo(E other)

那:

  • 需要使用 E 而不是枚举,这样您就不会尝试将一个枚举值与另一个枚举中的值进行比较
  • 需要能够通过ordinal() 获取枚举的序数值 方法Enum上声明。

您建议如何在没有当前限制的情况下实现这一目标?

这只是我想出的第一个……我相信还有很多其他的。基本上,它是一种说法,“你不应该尝试将所有枚举视为彼此等效......枚举本身是一个封闭的集合,但所有枚举都共享某些属性。”

Consider Enum<E>.compareTo(E other).

That:

  • Needs to work with E rather than enum so that you don't try to compare one enum value with a value from a different enum
  • Needs to be able to get the ordinal value of the enum, via the ordinal() method declared on Enum.

How would you propose making that work without the current constraint?

That's just the first one I came up with... I'm sure there are plenty of others. Basically it's a way of saying, "You shouldn't try to treat all enums as equivalent to each other... an enum is a closed set in itself, but all enums share certain properties."

探春 2024-09-13 06:57:55

如果您没有泛型类型参数,那么您将无法为您创建的枚举的特定子类型扩展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)< 的约定/代码>;如果您确实覆盖 equals,那么在某些情况下,x.equals(y) 并不意味着 x == y(对于其他值对象),而对于 Java 枚举来说,两者都是平等测试产生相同的结果。

If you didn't have the generic type parameter, then you wouldn't be able to extend Comparable<T extends Comparable> for the specific subtype of enum you have created.

You could ignore this, and create your own MyEnum type which behaves much the same but without the restriction that different MyEnum are not comparable:

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;
    }
}

This behaves in much the same way as an enum would for the operations defined, but instead of being a generic type safe implementation obeys LSP - objects of different subclasses of MyEnum are comparable or equal to each other if they have the same ordinal value.

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 ) );
}

In this case, if you don't override equals, you lose the convention that x.comparesTo(y)=0 implies x.equals(y); if you do override equals then there are cases where x.equals(y) does not imply x == y (as for other value objects), whereas for Java enums both tests of equality produce the same result.

我的鱼塘能养鲲 2024-09-13 06:57:55
`X extends Enum<Y>`

将是非法的。这是相关的。编译器可以对 enum 有特殊规则,但如果可能的话,为什么不拥有完美的类型声明呢?

`X extends Enum<Y>`

would be illegal. that is relavant. compiler can have special rules with enum, but why not have a perfect type declaration if possible?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文