How is it possible to group enums with a super type

Viewed 196

I'm currently working at a project where I have two different Enums that should be filled in an Array. I.e. my Array should be able to hold either one of the Enums. I'm aware that you can't implement inheritance for Enums as you could with classes.

Is there a way on how I can group my two Enums therefore I can put them into the same Array?

1 Answers

An enum in Java is implicitly a subclass of the Enum class. As with most object-oriented languages, Java does not support multiple inheritance. So your enum cannot be a subclass of any other class.

Share an interface

However… an enum can implement an interface. So define an interface to be implemented by both of your two enums.

For example, let's define an interface Breed, for various animal breeds.

package work.basil.demo.multienum;

public interface Breed
{
}

Define each of your two enums, both implementing that interface.

Some dogs.

package work.basil.demo.multienum;

public enum DogBreed implements Breed
{
    AUSTRALIAN_SHEPHERD , LABRADOR_RETRIEVER , BORDER_COLLIE
}

And cats.

package work.basil.demo.multienum;

public enum CatBreed implements Breed
{
    MAINE_COON , MANX , RUSSIAN_BLUE
}

Try them out in an example app.

package work.basil.demo.multienum;

import java.util.List;

public class App
{
    public static void main ( String[] args )
    {
        List <Breed> breeds =
                List.of(
                        DogBreed.BORDER_COLLIE,
                        CatBreed.RUSSIAN_BLUE,
                        CatBreed.MAINE_COON
                );

        System.out.println( "breeds = " + breeds );
    }
}

When run.

breeds = [BORDER_COLLIE, RUSSIAN_BLUE, MAINE_COON]

Whoops, I now see you asked for an array. Works the same way.

package work.basil.demo.multienum;

import java.util.Arrays;
import java.util.List;

public class App
{
    public static void main ( String[] args )
    {
        Breed[] breeds =
                List.of(
                        DogBreed.BORDER_COLLIE ,
                        CatBreed.RUSSIAN_BLUE ,
                        CatBreed.MAINE_COON
                )
                        .toArray( new Breed[ 0 ] );

        System.out.println( "breeds = " + Arrays.toString( breeds ) );
    }
}

In this example we did not define any methods on the interface Breed. Be aware that if you do add any methods there, both of the enums must implement those methods. The compiler will notify you if omitted.

Types and casting

You asked in a comment:

So, my Interface would work as a "super type" without defining anything to override. Do I understand this correctly?

Yes. Notice the declaration of array in my last example. The variable named breeds is an array of objects of type Breed (the interface) — not an array of CatBreed enum objects, nor an array of DogBreed enum objects.

You asked in a comment:

What happens if an enum implements a method on its own? e.g. CatBreed implements purr() method. Can I still access this method even though the type is Breed?

No. The elements of your array are all Breed objects. So when used as a Breed, such an object does not “see“ any method specific to CatBreed. A Breed object sees only the methods defined on the Breed interface.

To access your cat's purr method, you must cast the reference to a Breed object to be a reference to a CatBreed object. And you would first test using instanceof.

Breed breed = breeds.get( 1 )               // Index of 1 means second item, per annoying zero-based counting. We get `CatBreed.RUSSIAN_BLUE` as seen in the example code above.
if( breed instanceOf CatBreed )             // Test if the object referenced by `breed` happens to be also of type `CatBreed` besides being of type `Breed`.
{
    CatBreed catBreed = (CatBreed) breed ;  // Cast to that other type.
    …                                       // Use the `CatBreed` object named `catBreed` to access methods specific to `CatBreed` enum class.
}

Java 16 has a new feature, JEP 394: Pattern Matching for instanceof, to make the casting automatic.

Breed breed = breeds.get( 1 )               // We get `CatBreed.RUSSIAN_BLUE` from earlier example.
if( breed instanceOf CatBreed catBreed )    // Casting is automatic in Java 16 and later.
{
    …                                       // Use the `CatBreed` object named `catBreed` to access methods specific to `CatBreed` enum class.
}

Other related nifty features may be coming in the future because of further work being done with pattern matching, records, and sealed classes.


Caveat: This design (enums sharing an implemented interface) may or may not be an appropriate solution to a particular design problem. I have ignored the issue of appropriateness in my given example, for the sake of demonstrating this approach to a solution.

Related