为什么我们不允许我们在Java中的Enum中覆盖哈希码

发布于 2025-02-11 05:26:51 字数 847 浏览 1 评论 0 原文

我目前只知道,Java中没有ENUM的HashCode()实现。它返回的只是super.hashcode(),而其他不变类(例如字符串)都有自己的HashCode()实现。当跨不同的JVM使用时,这会使枚举不安全。我认为Ordinal()非常适合计算ENUM的hashCode(),但是枚举中的HashCode()定义为最终,我不能覆盖它。我唯一能想到的解决方案是为枚举创建一个全新的Simalar。有建议吗?


我想取得这样的目标:

enum Fruit {
        APPLE, POMEGRANATE, KIWI;
        
        @override
        public int hashCode() {
            return Objects.hash(super.ordinal());
        }
        @override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            }
            Fruit other = (Fruit)obj;
            return super.ordinal() == other.ordinal();
        }
}

有什么解决方案吗?或者 我想了解为什么此解决方案不好,因此在Java中不允许。

What I only know for now is that there is no implementation of hashCode() of Enum in java. what it returns is just super.hashCode() while other immutable class such as String all has its own implementation of hashCode(). This makes Enum unsafe when used across different JVM. I think ordinal() is perfect for calculating hashCode() of Enum, but the hashCode() in Enum is defined as final, I can't override it. The only solution I can think of is to create a brand new class simalar to Enum. Any suggestion?


I want to achieve something like this:

enum Fruit {
        APPLE, POMEGRANATE, KIWI;
        
        @override
        public int hashCode() {
            return Objects.hash(super.ordinal());
        }
        @override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            }
            Fruit other = (Fruit)obj;
            return super.ordinal() == other.ordinal();
        }
}

Any solution? or
I want to understand why this solution is bad and therefore not allowed in java.

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

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

发布评论

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

评论(1

吾家有女初长成 2025-02-18 05:26:51

你说:

这使得枚举在不同的JVM上使用。

您可以在任何对象上都依靠 hashcode 在jvms上保持一致的 hashcode ,例如commented by shmosel.

对象## HashCode 明确表示您不能依靠 hashcode 在JVM的调用之间相同。引用Javadoc:

此整数不必从一个执行应用程序到另一个应用程序执行。

的另一个执行。

你说:

我认为ordinal()非常适合计算枚举的hashcode()

否,我认为不是。您可以在应用程序版本之间定义枚举元素的顺序。您甚至可以添加或删除元素。因此,我们通常不应该依靠应用程序版本之间的序数。

你说:

我唯一能想到的解决方案是创建一个全新的Simalar来枚举。

我相信您在那里遇到麻烦。

你说:

有任何建议?

是的。分配密钥。

如果要识别由 enum 子类的对象表示的实体的值,我建议您将成员字段添加到枚举类中,以唯一地识别每个实例。

自然关键

您分配的价值取决于您的问题域。在特定行业或公司中,可能会有已知的标识符。例如,在处理水果时,也许可以分配拉丁科学植物名称。

在关系数据库理论中,其名称是天然键

enum Fruit {
    APPLE ( "Malus domestica" ) , 
    POMEGRANATE ( "Punica granatum" ) , 
    KIWI ( "Actinidia deliciosa" );
    
    final String botanicalName ;
    
    Fruit ( String botanicalName ) 
    {
        this.botanicalName = botanicalName ;
    }
}

用法:

for( Fruit fruit : Fruit.values() )
{
    System.out.println( fruit + " = " + fruit.botanicalName ) ;
}

运行时。

APPLE = Malus domestica
POMEGRANATE = Punica granatum
KIWI = Actinidia deliciosa

请参阅此 code在indeone.com 中实时运行。

代理密钥(任意标识符)

如果您的业务领域中没有此类标识符,则分配任意永久标识符。

如果您不知道一个,请使用普遍唯一的识别符(UUID)。请参阅 uuid 类。

在关系数据库理论中,我们称之为A 替代键

enum Fruit {
    APPLE ( UUID.fromString( "9307e05e-b337-41e8-acec-a00645b00878" ) ) , 
    POMEGRANATE ( UUID.fromString( "6f67df08-b400-49af-94ed-e068ee58412f" ) ) , 
    KIWI ( UUID.fromString( "028c9e8a-9d25-48a1-b150-b892ea26807f" ) ) ;
    
    final UUID id ;
    
    Fruit ( UUID id ) 
    {
        this.id = id ;
    }
}

用法:

for( Fruit fruit : Fruit.values() )
{
    System.out.println( fruit + " ➔ " + fruit.id ) ;
}

运行时。

APPLE ➔ 9307e05e-b337-41e8-acec-a00645b00878
POMEGRANATE ➔ 6f67df08-b400-49af-94ed-e068ee58412f
KIWI ➔ 028c9e8a-9d25-48a1-b150-b892ea26807f

顺便说一句,从技术上讲,“没有实现 hashcode() enum >”。继承的实现是其实现。该观点是 oop

You said:

This makes Enum unsafe when used across different JVM.

You can never rely on hashCode on any object to be consistent across JVMs, as commented by shmosel.

The contract promised by Object##hashCode says explicitly that you cannot rely on hashCode being the same between invocations of a JVM. To quote the Javadoc:

This integer need not remain consistent from one execution of an application to another execution of the same application.

You said:

I think ordinal() is perfect for calculating hashCode() of Enum

No, I think not. You can define the order of elements of an enum between releases of your app. You can even add or delete elements. So we should generally not rely upon ordinal number between versions of an app.

You said:

The only solution I can think of is to create a brand new class simalar to Enum.

I believe you are headed for trouble there.

You said:

Any suggestion?

Yes. Assign a key.

If you want to identify the value of the entities represented by your Enum subclass’ objects, I suggest you add a member field to your enum class to identify each instance uniquely.

Natural key

What value you assign depends on your problem domain. In a particular industry or company, there may be a known identifier. For example, in handling fruits, perhaps a Latin scientific botanical name could be assigned.

In relational database theory, the name for this is a natural key.

enum Fruit {
    APPLE ( "Malus domestica" ) , 
    POMEGRANATE ( "Punica granatum" ) , 
    KIWI ( "Actinidia deliciosa" );
    
    final String botanicalName ;
    
    Fruit ( String botanicalName ) 
    {
        this.botanicalName = botanicalName ;
    }
}

Usage:

for( Fruit fruit : Fruit.values() )
{
    System.out.println( fruit + " = " + fruit.botanicalName ) ;
}

When run.

APPLE = Malus domestica
POMEGRANATE = Punica granatum
KIWI = Actinidia deliciosa

See this code run live at Ideone.com.

Surrogate key (arbitrary identifier)

If no such identifier exists in your business domain, then assign an arbitrary permanent identifier.

If you have no idea of one, then use a universally unique identifier (UUID). See the UUID class.

In relational database theory, we call this a surrogate key.

enum Fruit {
    APPLE ( UUID.fromString( "9307e05e-b337-41e8-acec-a00645b00878" ) ) , 
    POMEGRANATE ( UUID.fromString( "6f67df08-b400-49af-94ed-e068ee58412f" ) ) , 
    KIWI ( UUID.fromString( "028c9e8a-9d25-48a1-b150-b892ea26807f" ) ) ;
    
    final UUID id ;
    
    Fruit ( UUID id ) 
    {
        this.id = id ;
    }
}

Usage:

for( Fruit fruit : Fruit.values() )
{
    System.out.println( fruit + " ➔ " + fruit.id ) ;
}

When run.

APPLE ➔ 9307e05e-b337-41e8-acec-a00645b00878
POMEGRANATE ➔ 6f67df08-b400-49af-94ed-e068ee58412f
KIWI ➔ 028c9e8a-9d25-48a1-b150-b892ea26807f

By the way, it is technically incorrect to say “there is no implementation of hashCode() of Enum”. The inherited implementation is its implementation. This perspective is fundamental to OOP.

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