A Java enumeration, also known as a Java enumeration type, is a type where a field consists of a fixed set of constants. The primary purpose of enumerations is to enforce compile-time type security. The enum keyword is a reserved keyword in Java.

When compiling or designing, try to use enumerated types when we know all the possibilities for variables. This article will take you a comprehensive and systematic understanding of the use of enumeration, and some of the problems encountered.

Enumerations in Java

Enumerations are usually a set of related constants, and other programming languages have long used them, such as C++. Since JDK1.5, Java has also begun to support enumerated types.

Enumerations are a special type of data type that is a class type but has more special constraints than a class type. These constraints contribute to the simplicity, security, and convenience of enumerations.

In Java, enum types are declared through enums, inherited by default from java.lang.enum. So when you declare an enumerated class, you can no longer inherit from other classes.

Enumeration declarations

In daily life, we will often identify the direction, east, west, east, west, their names, attributes and so on are basically determined, we can declare them as enumerated type:

public enum Direction { EAST, WEST, NORTH, SOUTH; } Similarly, seven days a week can be declared as enumerated:

Enum Day {MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY} We can define constants by class or interface:

public class Day {

public static final int MONDAY =1;

public static final int TUESDAY=2;

public static final int WEDNESDAY=3;

public static final int THURSDAY=4;

public static final int FRIDAY=5;

public static final int SATURDAY=6;

public static final int SUNDAY=7;
Copy the code

} However, this has many disadvantages, such as type safety and ease of use. If there are variables that define the same int value, the chances of confusion are high and the compiler will not raise any alarm. Therefore, this approach is not recommended when enumerations are available.

An underlying implementation of enumeration

As we said above, an enumeration is a special class, and each enumeration item is essentially an instance of the enumeration class itself.

Thus, the above enumerated class Direction can be used as an example with the following code:

final class Direction extends Enum{ public final static Direction EAST = new Direction(); public final static Direction WEST = new Direction(); public final static Direction NORTH = new Direction(); public final static Direction SOUTH = new Direction(); } javac (Direction) {javap (Direction);

bogon:enums apple$ javap Direction.class Compiled from “Direction.java” public final class com.choupangxia.enums.Direction extends java.lang.Enum<com.choupangxia.enums.Direction> { public static final com.choupangxia.enums.Direction EAST; public static final com.choupangxia.enums.Direction WEST; public static final com.choupangxia.enums.Direction NORTH; public static final com.choupangxia.enums.Direction SOUTH; public static com.choupangxia.enums.Direction[] values(); public static com.choupangxia.enums.Direction valueOf(java.lang.String); static {}; } You can see that an enumeration, when compiled by the compiler, becomes an abstract class that inherits java.lang.enum; The enumeration constant defined in the enumeration becomes the corresponding public Static final property, and its type is the type of the abstract class. Its name is the name of the enumeration constant.

Enumeration Example

As we can see from the decompression above, the enumeration option is essentially a public static final variable, so just use it as such.

public class EnumExample { public static void main(String[] args) { Direction north = Direction.NORTH; System.out.println(north); // NORTH}} ordinal() method of enumeration

The ordinal() method is used to get the order in which enumeration variables are declared in an enumeration class, with subscripts starting at 0, much like those in an array. It is designed for use with complex enumeration-based data structures such as EumSet and EnumMap.

Direction.EAST.ordinal(); / / 0

Direction.NORTH.ordinal(); //2 Note that if the position of the enumeration item declaration changes, the ordinal method changes with it. Therefore, avoid using this method in the past. Otherwise, when there are too many enumerations, someone adds or deletes an item in the middle, resulting in all subsequent order changes.

Enumerated values() and valueOf()

The values() method takes all the variables in the enumerated class and returns them as an array:

Direction[] directions = Direction.values();

for (Direction d : directions) { System.out.println(d); }

//Output:

The EAST WEST NORTH SOUTH values() method is a static method inserted by the compiler into an Enum class that does not exist in its parent Enum class.

The valueOf(String Name) method is similar to the valueOf method in the Enum class. It is also generated by the compiler, but it is more concise and requires only one parameter.

Direction east = Direction.valueOf(“EAST”);

System.out.println(east);

//Output:

EAST enumeration naming convention

By convention, enumerations are constants, so all letters are UPPER_CASE and underlined (UPPER_CASE). That is, enumeration class names are the same as normal class conventions, and variables in enumeration are named the same as static variables.

Enumeration constructor

By default, enumeration classes do not require constructors, and the default variable is the string at which they are declared. Of course, you can also initialize some of the enumeration’s state information by customizing the constructor. Normally, we pass two parameters in the construct parameter, for example, an encoding and a description.

Take the above directions for example:

public enum Direction { // enum fields EAST(0), WEST(180), NORTH(90), SOUTH(270);

// constructor
private Direction(final int angle) {
    this.angle = angle;
}

// internal state
private int angle;

public int getAngle() {
    return angle;
}
Copy the code

} If we want to access the Angle in each direction, we can do this by simply calling:

Direction north = Direction.NORTH;

System.out.println(north); //NORTH

System.out.println(north.getAngle()); / / 90

System.out.println(Direction.NORTH.getAngle()); // methods in the enumeration

Enumerations are a special class, so they can have methods and attributes just like normal classes. Enumerations allow you to declare not only concrete methods, but also abstract methods.

Methods can be private, protected, or public. You can use these methods to return the value of an enumerated item, or you can do some internal private processing.

public enum Direction { // enum fields EAST, WEST, NORTH, SOUTH;

protected String printDirection() { String message = &quot; You are moving in &quot; + this + &quot; direction&quot;; System.out.println( message ); return message; }Copy the code

} The corresponding method is used as follows:

Direction.NORTH.printDirection(); Direction.EAST.printDirection(); Enumeration classes can also define abstract methods, but each enumeration item must implement the corresponding abstract method:

public enum Direction { // enum fields EAST { @Override public String printDirection() { String message = “You are moving in east. You will face sun in morning time.”; return message; }}, WEST { @Override public String printDirection() { String message = “You are moving in west. You will face sun in evening time.”; return message; }}, NORTH { @Override public String printDirection() { String message = “You are moving in north. You will face head in daytime.”; return message; } }, SOUTH { @Override public String printDirection() { String message = “You are moving in south. Sea ahead.”; return message; }};

public abstract String printDirection();
Copy the code

} Abstract method calls, just like normal methods:

Direction.NORTH.printDirection(); Direction.EAST.printDirection(); In this way, it is easy to define a different behavior for each enumerated instance. Such an abstract method could be defined if, for example, each enumeration item needed to print out the direction name.

The above instance enum class seems to exhibit polymorphic properties, but instances of enumerated types cannot be passed as types after all. The compiler cannot pass either of the following ways:

Direction.NORTH is an instance object public void text(direction. NORTH instance){} enumeration

As mentioned above, enumerations inherit from java.lang.Enum, which is an abstract class:

public abstract class Enum<E extends Enum> implements Comparable, Serializable { // … } That is, all enumerated classes support Comparable and Serializable features. Because all enumerated classes inherit enums, they can’t inherit from other classes, but they can implement interfaces.

Comparison of enumerations

All enumerations are Comparable and singletons by default, so they can be compared through the equals method or even directly with the double equal sign “==”.

Direction east = Direction.EAST; Direction eastNew = Direction.valueOf(“EAST”);

System.out.println( east == eastNew ); //true System.out.println( east.equals( eastNew ) ); //true Enumeration set: EnumSet and EnumMap

Two enumerated collection classes are introduced under the java.util package: EnumSet and EnumMap.

EnumSet

The EnumSet class is defined as follows:

public abstract class EnumSet<E extends Enum> extends AbstractSet implements Cloneable, java.io.Serializable{ // … } EnumSet is a specialized Set to be used with enumeration types. All elements in an EnumSet must be of enumeration type. Unlike the other Set interface implementation class HashSet/TreeSet, EnumSet is internally implemented as a bit vector.

Bit vector is an extremely efficient bit operation. As both the direct storage and operation are bits, EnumSet has considerable space and time performance, which is comparable to the traditional “bit flag” operation based on INT. The key is that we can operate bit operation like set.

EnumSet does not allow the use of null elements. Attempting to insert a NULL element will throw a NullPointerException, but tests to determine the presence or removal of null elements will not throw an exception. EnumSet, like most Collection implementations, is not thread-safe. Pay attention to data synchronization in multi-threaded environments.

Example:

public class Test { public static void main(String[] args) { Set enumSet = EnumSet.of( Direction.EAST, Direction.WEST, Direction.NORTH, Direction.SOUTH ); } } EnumMap

EnumMap is declared as follows:

public class EnumMap<K extends Enum, V> extends AbstractMap<K, V> implements java.io.Serializable, Cloneable {} Similar to EnumSet, EnumMap is a special Map whose Key must be an enumeration type. EnumMap is implemented through arrays, which is more efficient than ordinary maps. The key value of EnumMap cannot be null, and EnumMap is not thread-safe.

The following is an example of EnumMap:

public class Test { public static void main(String[] args){ //Keys can be only of type Direction Map enumMap = new EnumMap(Direction.class);

//Populate the Map
enumMap.put(Direction.EAST, Direction.EAST.getAngle());
enumMap.put(Direction.WEST, Direction.WEST.getAngle());
enumMap.put(Direction.NORTH, Direction.NORTH.getAngle());
enumMap.put(Direction.SOUTH, Direction.SOUTH.getAngle());
Copy the code

}} Enumeration with switch

When using switch to judge conditions, conditional parameters can only be integers, characters, and enumerations. After java7, switch also supports strings.

Examples are as follows:

enum Color {GREEN,RED,BLUE}

public class EnumDemo4 {

Public static void printName(Color Color){switch (Color){case BLUE: system.out.println (" BLUE "); case BLUE: system.out.println (" BLUE "); break; Case RED: system.out.println (" RED "); break; Case GREEN: system.out.println (" GREEN "); break; } } public static void main(String[] args){ printName(Color.BLUE); printName(Color.RED); printName(Color.GREEN); }Copy the code

} enumerations versus singletons

Singleton pattern is one of the most common design patterns in daily use, singleton implementation has many kinds of implementation methods (hungry man pattern, lazy pattern, etc.), here is no longer described, only to a most common singleton to do contrast, and then see how to implement singleton pattern based on enumeration.

Realization of hungry and Han Mode:

public class Singleton {

private static Singleton instance = new Singleton();

private Singleton() {
}

public static Singleton getInstance() {
    return instance;
}
Copy the code

} is simple and straightforward, with the disadvantage that instances can be created before they are needed, rather than being lazy. The advantage is that the implementation is simple, and safe and reliable.

Such a singleton scenario, if implemented through enumeration, would look like this:

public enum Singleton {

INSTANCE;

public void doSomething() {
    System.out.println("doSomething");
}
Copy the code

} in Effective Java, the best singleton implementation pattern is the enumeration pattern. Let the JVM help us with thread safety and single instance issues by taking advantage of enumerations. In addition, the writing method is very simple.

Directly through the Singleton. INSTANCE. DoSomething () call. Convenient, simple and safe.

summary

Enumeration is almost essential in daily coding, how to use well, how to use fine, but also need the foundation of basic knowledge, this article is based on this with everyone combed from beginning to end. Give it a thumbs up when you get something.