Java Enums can implement Interfaces

Main menu:

Topics

Recent Posts

Blog

June 2011
M T W T F S S
« May   Jul »
 12345
6789101112
13141516171819
20212223242526
27282930  

Past Posts

Java/Java EE

JDBC

Other

Java Enums can implement Interfaces

June 15th, 2011 by David O'Meara

Something which came as a surprise to me but ended up quite useful, was that enums in Java can also implement interfaces.

A typical enumeration in Java, introduced in Java 5, looks like a String value, but also introduces other features which make them a particularly useful language feature. Besides looking like an typical enumeration with a finite ordered list of values, it is also possible to attach additional information to each enumeration value.

A basic enumeration, which defines the four suits in a typical set of cards looks like this:

public enum Suit 
{ CLUBS, DIAMONDS, HEARTS, SPADES }

To attach additional information to the enumerated type, add a private constructor, add a private field, and get each enumeration value to call the new constructor.

public enum Numbers {
	One(1), Two(2), Three(3);

	private Numbers(int value)
	{
		this.value = value;
	}
	
	public int getValue()
	{
		return this.value;
	}
	
	private int value;
}

In the example above, we also introduced the getValue() method. This introduces the concept of behaviour to our enumeration; not something we would normally consider. It also lends itself to the idea of common behaviour between enumerated types.

To show how this works, consider an interface which defines the mapping between a class and a table.

public interface DatabaseMapping {
	public String getType();
	public boolean isKey();
	public boolean isNullable();
	//public String name();
}

The method name() is commented for now, we’ll get back to that in a minute.

To use this, we can now create a new Java class and then define the mapping of that class to a database.

public class Person {
	public String getFirstname() {
		return firstname;
	}
	public void setFirstname(String firstname) {
		this.firstname = firstname;
	}
	public String getLastname() {
		return lastname;
	}
	public void setLastname(String lastname) {
		this.lastname = lastname;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	private String firstname;
	private String lastname;
	private int age;
}

(I realise there are better ways to map a class to a database table, this example is contrived) When we define the mapping from our class to our table, we can define a separate mapping class. We create this class, we will make it an enumeration and allow each class/database field to be a member in an enumeration.

public enum PersonMapping {
	personId, firstname, lastname, age;
}

Using the trick where we are able to attach additional information to enumerated types, we define some of the database mapping details:

public enum PersonMapping {
	personId("INTEGER", true, false), 
	firstname("TEXT", false, false), 
	lastname("TEXT", false, false),
	age("INTEGER", false, false);
	private PersonMapping(String type, boolean key, boolean nullable )
	{
		this.type = type;
		this.key = key;
		this.nullable = nullable;
	}
	public String getType() {
		return type;
	}
	public boolean isKey() {
		return key;
	}
	public boolean isNullable() {
		return nullable;
	}
	private final String type;
	private final boolean key;
	private final boolean nullable;
}

So now we are able to use the enumeration to iterate the fields and do some database stuff. For the moment we’ll hold off including the interface.

public String dbTableCreate(String tableName) {
	StringBuilder builder = new StringBuilder("Create table ");
	builder.append(tableName);
	builder.append("(");
	for (PersonMapping column : PersonMapping.values()) {
		builder.append(column.name());
		builder.append(" ");
		builder.append(column.getType());
		builder.append(column.isKey() ? " primary key" : "");
		builder.append(", ");
	}
	builder = new StringBuilder(builder.substring(0, builder.length() - 2));
	builder.append(");");
	return builder.toString();
}

Which looks fine for our PersonMapping enumerated type, but doesn’t allow us to plug in different class-to-database mappings. Time to introduce the interface. Looking closely at the code above, we need to use two of the additional methods available to all enumerations, name() and values(). The first returns the text name of the current enumerated value, and the second allows us to access the values that make up this enumerated type.

First add the interface to the enumeration:

public enum PersonMapping implements MappingEnum{

Uncomment the name() method so that it can be accessed from the interface.

public interface MappingEnum {
	public String getType();
	public boolean isKey();
	public boolean isNullable();
	public String name();
}

Final piece of the puzzle is to write the dbTableCreate() above to allow it to be reused with other enumerated types. The problem we need to work around is that the values() method is static, making it difficult to pass the enumerated type to the method. The simple solution is to call the method explicitly and pass the values:

dbTableCreate("tableName", PersonMapping.values()));

… and realise that we can now receive the values using the interface …

public String dbTableCreate(String tableName, MappingEnum[] values) {
	StringBuilder builder = new StringBuilder("Create table ");
	builder.append(tableName);
	builder.append("(");
	for (MappingEnum column : values) {
		builder.append(column.name());
		builder.append(" ");
		builder.append(column.getType());
		builder.append(column.isKey() ? " primary key" : "");
		builder.append(", ");
	}
	builder = new StringBuilder(builder.substring(0, builder.length() - 2));
	builder.append(");");
	return builder.toString();
}

Conclusion

* Enumerations can store additional data and have additional methods,
* Enumerations can use interfaces to define behaviour,
* Enumerated item behaviour can be accessed via an interface, the same as regular Java classes,
* The values() method from enumerations can be used to return an array of a interface.

Combined, it allows us to treat enumerated types as both regular Java classes and enumerated types and interact using common behaviour rather than being tied to a single implementation.

Comments

Comment from kjordan
Posted: June 15, 2011 at 6:36 pm

Well, an enum does just become in byte code a compiler generated class that extends an actual class called Enum where each value inside the enum is just a static instance inside that generated class which are inserted into an array that values() returns. This means since it already extends Enum you can’t extend anything else, but as you’v realized you can do anything else to it that you can do to a regular class.

Comment from David O’Meara
Posted: June 15, 2011 at 9:00 pm

absolutely, and my initial mistake was in thinking a Java enum was something special or separate within the Java system. As you have said the byte code threats it is Class and it may be that modifying the code to be aware of the Enum superclass (maybe mix in some Generics) could allow me to improve the final code rather than calling the static Enum.values() and then accepting an array of an interface type.
I don’t see this as being widely used, but I found it a handy feature.

Comment from Bogdan Marian
Posted: June 16, 2011 at 2:45 am

Hello,
Please note that the Java tutorials clearly states that an enum is in fact a class, so of course it can implement an interface ;) (http://download.oracle.com/javase/tutorial/java/javaOO/enum.html – “… The enum declaration defines a class …”).

Comment from David O’Meara
Posted: June 16, 2011 at 10:40 pm

agreed, but I’m talking about interfaces allowing common behaviour between different enumerated types _because_ they are classes. Hence surprising but should not have been :)

Comment from Luis Matos
Posted: June 26, 2013 at 8:31 am

Thanks a lot, that’s exactly what I was searching for. Very helpful.
Did you ever check whether there was a better way to work with the static Enum.values()? It would surely improve the solution.

Write a comment