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.