Home > Mobile >  Why are we not allowed to override hashcode in enum in java
Why are we not allowed to override hashcode in enum in java

Time:06-28

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?

CodePudding user response:

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.

CodePudding user response:

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.

  • Related