Description Enumeration type Enum

1. What are enumerated types

Enumerated types: A new type is made up of a finite set of values with names. (the new class).

Let’s take a look at why we introduced enumerations

Before we introduced enumerated types, we did this when we wanted to maintain a set of constants, as shown in the following example:

class FavouriteColor_class{
    public static final  int RED   = 1;
    public static final  int BLACK = 3;
    public static final  int GREEN = 2;
    public static final  int BLUE  = 4;
    public static final  int WHITE = 5;
    public static final  int BROWN = 6;
}
Copy the code

When we have an enumerated type, we can abbreviate it to:

/ / enumerated type public enum FavouriteColor {/ / enumeration members RED, GREEN, BLACK, BLUE, WHITE, BROWN,}Copy the code

Isn’t it simple and clear? This saves a lot of repetitive code and makes it easier to maintain.

Now you understand the definition of enumerated types a little bit. To be more specific, ** uses the keyword enum to create a new class class from a finite set of constants. ** For the new class type, read on.

Second, in-depth analysis of the characteristics and implementation principle of enumeration

This is just a brief introduction to the simplest uses of enumerations. We’ll take a step-by-step look at the complex uses of enumerations and how they work.

1. Enumerators

The members of FavouriteColor are enumerators. In other words, enumerators are members of an enumerator class that have no type modifications, only variable names, and cannot be assigned values.

Still confused about enumerators, let’s decompile the above example:

public final class FavouriteColor extends Enum {

    public static final FavouriteColor RED;
    public static final FavouriteColor GREEN;
    public static final FavouriteColor BLACK;
    public static final FavouriteColor BLUE;
    public static final FavouriteColor WHITE;
    public static final FavouriteColor BROWN;
}
Copy the code

As you can see from the decompression, enumerators are treated as static enumeration constants that are public static final. That is, the enumerators in the above example are all instances of the enumerator class FavouriteColor.

2. Add methods, constructors, and non-enumerable members for enumeration types

When adding methods, constructors, and non-enumerators, enumerated types are not much different from normal classes, except for the following restrictions:

  • Enumerators must be declared first and only on one line (separated by commas and terminated by semicolons).
  • Constructor access must be private (optional, mandatory by default), not public or protected.
Public enum FavouriteColor {/ / enumeration members RED, GREEN, (2), BLACK (3), BLUE, WHITE, BROWN; // Must have a semicolon // non-enumeration member private int colorValue; public int aa; Public static final int cc = 2; // No parameter constructor privateFavouriteColor() {} // FavouriteColor(int colorValue) {this.colorValue = colorValue; } // method public voidprint() { System.out.println(cc); }}Copy the code

As you can see, we can actually do a lot with the Eunm type, although we generally only use plain enumerated types.

A closer look at all the enumerators shows that the GREEN(2) and BLACK(3) enumerators are a bit strange! So GREEN(2) and BLACK(3) can be used as a parameter constructor, so if you are a FavouriteColor GREEN = new FavouriteColor(2), you can call them FavouriteColor. Several other enumerated types represent objects created using a no-parameter constructor. (In fact, the compiler recreates each constructor, adding two more arguments to each constructor.)

3. Enumeration types containing abstract methods

Enumeration types are also allowed to contain abstract methods (except for a few minor limitations, enumeration classes are almost the same as normal classes). What about enumerators for enumeration types that contain abstract methods, and how does the compiler handle them?

As we know, the decompilation of FavouriteColor class in the example above is a final class that inherits Enum:

public final class FavouriteColor extends Enum 
Copy the code

Are enumerations containing abstract methods also treated by the compiler as final classes, and if so, how are they inherited by subclasses? Or is it an abstract class?

Let’s look at an example of an enumeration class that contains abstract methods. The Fruit class has three fruits and we want to output information for each Fruit:

public enum Frutit {

    APPLE {
        @Override
        public void printFruitInfo() {
           System.out.println("This is apple");
        }
    },BANANA {
        @Override
        public void printFruitInfo() {
            System.out.println("This is apple");
        }
    },WATERMELON {
        @Override
        public void printFruitInfo() {
            System.out.println("This is apple"); }}; // Abstract method public abstract voidprintFruitInfo(); public static void main(String[] arg) { Frutit.APPLE.printFruitInfo(); }}Copy the code

Running results:

This is apple

It is also easy to understand the form of the enumerator above, because an enumerator is an instance of an enumerator type. The form above is an anonymous inner class, that is, each enumerator creation can be understood as:

    BANANA = new Frutit("BANANA", 1) {// This constructor is generated by the compiler and will say public void belowprintFruitInfo() {// Abstract method implementation of an anonymous inner class. System.out.println("This is apple"); }};Copy the code

In fact, that’s exactly what the compiler does: in the example above, three anonymous inner classes are created, along with three more class files.

Finally, let’s decompile the fruit class and look at the fruit class definition:

public abstract class Frutit extends Enum
Copy the code

The Fruit class is treated as an abstract class, so it can be said that enumeration types are treated by the compiler, and those with abstract methods are treated as abstract classes, otherwise final classes.

4. The parent class of the Enum type — Enum

Each enumerated type inherits an Enum, so it’s important to know about enums;

public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {// Enumeration member name private final String name; Private final int ordinal; private final int ordinal; // Constructor protected Enum(String name, int ordinal) {this.name = name; this.ordinal = ordinal; } public final intordinal() {// Returns the ordinal number of the enumeration constantreturn ordinal;
    }
 }

 public final String name() {// Returns the name of this enumeration constant to declare in its enumeration declaration.return name;
    }

 public final boolean equals(Object other) {
        returnthis==other; } public final inthashCode() {
        returnsuper.hashCode(); } public final int compareTo(E o) {public static <T extends Enum<T>> T valueOf(Class<T> enumType, String name) { } public StringtoString() {
        return name;
    }
Copy the code

The above are some of the methods that might be used, and we can see two interesting things from the above:

  • The Enum class implements the Serializable interface, which means that you can enumerate types and serialize them.
  • Almost all methods of Enum are final, that is, enumeration types can override only toString(), not other methods, not even hashcode(), equal(), and so on.

5. Really understand how enumerated types work

The above mentioned so much, are one-sided, simple understanding of enumeration types, but have not fully grasped the nature of enumeration types, with the above foundation, we will be like a duck to water.

To really understand the nature of enumerated types, you need to understand how the compiler handles them, the old-fashioned way: decompilation. This time to look at a complete decompilation code, first look at an example:

public enum Fruit {

    APPLE ,BANANA ,WATERMELON ;
    
    private int value;
    
    private Fruit() {// Default constructor this.value = 0; } private Fruit(int value) {this.value = value; }}Copy the code

Result of decompilation:

Public final class Fruit extends Enum {public final Fruit class extends Enum; public static final Fruit BANANA; public static final Fruit WATERMELON; private int value; Private static final Fruit ENUM$VALUES[]; APPLE = new Fruit(APPLE = new Fruit)"APPLE", 0);
        BANANA = new Fruit("BANANA", 1);
        WATERMELON = new Fruit("WATERMELON", 2);
        ENUM$VALUES= (new Fruit[]{APPLE, BANANA, WATERMELON}); } private Fruit(String s, int I) {private Fruit(String s, int I) { value = 0; } private Fruit(String s, int I, int value) {// Super (s, I); this.value = value; } public static Fruit[]values() {// the compiler added static values() Fruit afruit[]; int i; Fruit afruit1[]; System.arraycopy(afruit = ENUM$VALUES, 0, afruit1 = new Fruit[i = afruit.length], 0, i);
        returnafruit1; } public static Fruit valueOf(String s) {return(Fruit) Enum.valueOf(Test_2018_1_16 / Fruit, s); }}Copy the code

As you can see from the decompilation, the compiler did a lot of work for the enumerated class we created:

The compiler treats all enumerators as public static final enumeration constants and initializes them in static fields. – Constructor The compiler redefines constructors, adding not only two more parameters for each constructor, but also constructor calls for the parent class. – Added two class methods The compiler adds values() and valueOf() to the enumeration class. The values() method returns an array of enumerated types that can be used to iterate over the enumerated types. The valueOf() method is also new and overrides the parent valueOf() method

Note: Because the real constructor for an enumerated type is generated at recompilation time, we cannot create instances of enumerated types and inherit extended enumerated types (even if they are treated as abstract classes). Instances of enumerated types can only be created by the compiler

The use of enumeration types

1. switch

    Fruit fruit = Fruit.APPLE;

    switch (fruit) {
    case APPLE:
        System.out.println("APPLE");
        break;
    case BANANA:
        System.out.println("BANANA");
        break;
    case WATERMELON:
        System.out.println("WATERMELON");
        break;
    }
Copy the code

2. Implement interfaces

Not much to say about implementing interfaces. Enumeration types inherit from Enum classes, so they can’t inherit from other classes, but they can implement interfaces.

3. Use interfaces to organize enumerations

As mentioned earlier, enumerated types cannot be extended by subclass inheritance, which makes it impossible to meet the following two requirements:

  • You want to extend elements from the original enumerated type;
  • You want to use subclasses to group elements in an enumerated type;

There are several Food categories under Food, and the specific Food is in the category.

public interface Food { enum Appetizer implements Food { SALAD, SOUP, SPRING_ROLLS } enum Coffee implements Food { BLACK_COFFEE, DECAF_COFFEE, ESPERSSO, TEA; } enum Dessert implements Food { FRUIT, GELATO, TIRAMISU; }}Copy the code

The Food interface is a category, and the three enumerated types are subclasses of the interface. Food manages these enumerated types. For enumerations, implementing the interface is the only way to subclass them, so each enumeration class nested in Food implements the Food interface. So “all of this stuff is some type of Food.”

Food food = Food.Coffee.ESPERSSO; //ESPERSSO is not only a coffee, but also a category of FoodCopy the code

4. Use enumeration to implement the singleton pattern

For serialization and deserialization, because each enumeration type and enumeration variable is unique within the JVM, Java makes special provisions when serializing and deserializing enumerations, Enumeration methods such as writeObject, readObject, readObjectNoData, writeReplace, and readResolve are disabled by the compiler, so for enumeration singletons, There is no problem that calling readObject after implementing the serialization interface will break the singleton. Therefore, enumerating singletons is the best way to implement the simple interest pattern.

public enum EnumSingletonDemo { SINGLETON; // Other methods, members, etc public intotherMethod() {
        return0; }}Copy the code

How singletons are used:

int a = EnumSingletonDemo.SINGLETON.otherMethod();
Copy the code

EnumSet EnumMap

This is a brief introduction to the use of these two classes, not an in-depth analysis of how they are implemented.

1, enumsets

EnumSet is an abstract class derived from AbstractSet, which is essentially a Set**. Except that Enumset is a specialized Set implementation to be used with enumeration types. All keys in an enumeration set must come from a single enumeration type that explicitly or implicitly specifies ** when the set is created.

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
Copy the code

Although the JDK does not provide an implementation subclass of EnumSet, the methods added to EnumSet are static, and they are the objects used to create an EnumSet. Therefore, it can be thought of as a Set that operates on elements in an enumeration, and has high performance. Look at the following example:

Public static void main(String[] args) {// Create an object and specify EnumSet. EnumSet<FavouriteColor>set= EnumSet.allOf(FavouriteColor.class); // Remove the enumerator set.remove(Favouritecolor.black); set.remove(FavouriteColor.BLUE);for(FavouriteColor color : set{/ / traversesetSystem.out.println(color); }}Copy the code

Running results:

RED GREEN WHITE BROWN

EnumSet does not support synchronous access. Thread safety can be achieved by:

Set<MyEnum> s = Collections.synchronizedSet(EnumSet.noneOf(MyEnum.class));
Copy the code

2. EnumMap

EnumMap is a class that is also a specialized Map implementation used with enumeration type keys. All keys in an enumeration map must come from a single enumeration type that is specified explicitly or implicitly when the map is created. Enumeration maps are internally represented as arrays. This representation is very compact and efficient.

public class EnumMap<K extends Enum<K>, V> extends AbstractMap<K, V>
Copy the code

Simple use examples:

public static void main(String[] args) {
        
    EnumMap< FavouriteColor,Integer> map = new EnumMap<>(FavouriteColor.class); 
    map.put(FavouriteColor.BLACK,1 );
    map.put(FavouriteColor.BLUE, 2);
    map.put(FavouriteColor.BROWN, 3);
         
    System.out.println(map.get(FavouriteColor.BLACK));
}
Copy the code

Also, to prevent accidental synchronization operations:

Map<EnumKey, V> m = Collections.synchronizedMap(new EnumMap<EnumKey, V>(...) );Copy the code

Conclusion:

  • Enumeration types inherit from Enum classes, so they can only be used to implement interfaces, not other classes.
  • Enumerated types are treated by the compiler as abstract classes (with abstract methods) or final classes.
  • Enumerators are public static final enumerator instance constants. Enumerators must be declared first and on only one line (separated by a comma and terminated by a semicolon).
  • The constructor must be private, and if you define a constructor with parameters, pay attention to the declaration of enumerators. When no constructor is defined, the compiler automatically adds a two-parameter constructor to the enumerated class, not a no-parameter constructor.
  • The compiler adds values() and valueOf() methods to the enumeration class.
  • Enumeration classes with no abstract methods are treated as final by the compiler. An enumeration class containing an abstract method is treated as an abstract abstract class.
  • Enum implements the Serializable interface and almost all methods are final

Reference: http://www.cnblogs.com/jinggod/p/8503281.html

If there are any improper articles, please correct them. You can also pay attention to my wechat public number: Learn Java well and get high quality resources.