Follow the public account: Java big data and data warehouse, learn big data technology
Enumeration met
The full name of enum is enumeration. In Java, types that are qualified by the enum keyword are enumeration types. For example enum {RED, BLUE, WHITE, BLACK}
Enumerated types are part of the new Java 5 feature set. They are a special type of data that is special because they are a class type but have more special constraints than class types. But these constraints also contribute to the simplicity, security, and convenience of enumerated types.
Benefits of enumerations: Constants can be organized and managed uniformly. Enumeration typical application scenario error codes and state machines.
Let’s take a look at the following program. This is a common way to define constants without enumerating types. It is still defined and used today, but there is nothing wrong with it
public class DateNoneEnum {
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
Int the way of the constants defined constants known as enumeration mode, of course there are other patterns, such as string enumeration mode, so there’s nothing wrong with the definition of the way, but it has many deficiencies, such as on the type safety and use convenience and don’t have much good, if there is the same Int value variables, confuse the odds is very big still, The compiler doesn’t raise any red flags, so this is not recommended after enumerations. Now let’s use enumeration types to redefine the above constants, and also feel the way enumerations are defined, as follows: Define constants from Monday to Sunday
public enum DateEnum {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY
}
Copy the code
Quite succinctly, the keyword we use to define enumeration types is enum, similar to the class keyword, except that the former defines enumeration types and the latter defines class types.
The enumeration type DateEnum defines values from Monday to Sunday. Note that enumeration values are generally capitalized and separated by commas.
We should also be aware that enumerations can be defined in a single file, just like class types, or within other classes. More importantly, enumerations are safe and convenient, and the compiler will prompt us to improve if there is a type problem. But keep in mind that enumerations must be finite, meaning that each value can be enumerated, such as the seven days of the week described above. (There are many things that cannot be enumerated, such as integer values, which are infinite.)
So how do you use it? As follows:
public class EnumDemo {
@Test
public void useEnum(a) { DateEnum dateEnum = DateEnum.MONDAY; }}Copy the code
As in the above code, simply referring to the value of an enumeration is the simplest model for enumeration types.
Implementation principle of enumeration
Enumeration that inherits from the Enum abstract class
Now that we’ve looked at the definition and simple use of enumerated types, it’s worth looking at the basics of how enumerated types are implemented.
In fact, after creating the enum type using the keyword enum and compiling it, the compiler generates an associated class for us that inherits the java.lang. enum class from the Java API, That is, creating an enumerated type with the keyword enum is actually a class type when compiled and inherits from the java.lang. enum class.
Let’s verify this by compiling the dateenm.java defined earlier and viewing the generated class file:
Java file, and then we look at the generated dateenum. class. This verifies that when we define enum types using the keyword enum and compile them, the compiler will automatically help us generate a class associated with enumeration.
As you can see from the decomcompiled code, the compiler did help us generate a DateEnum class. Note that this class is final and will not be inherited, and it inherits from the Java.lang. Enum class, which is abstract (we’ll look at the main methods in this class later).
DateEnum: public static final DateEnum: public static final DateEnum: public static final DateEnum: public static final DateEnum: public static final DateEnum
This also fully demonstrates that each date enumeration constant in the DateEnum type we defined earlier using the keyword enum is also an actual DateEnum class object
Note that the compiler also generates two static methods for us, values() and valueOf(). We’ll see how they are used later, so we can see that an enum type defined with the keyword enum is converted to an actual class at compile time. Public Static Final DateEnum MONDAY; Public static final DateEnum MONDAY; , and the compiler creates two methods for the class, values() and valueOf().
The Java class java.lang.Enum () and values() and valueOf() are used for enumeration. The Enum class is an abstract class. That is, the inheritance relationship between the specification of java.lang.Enum and the class
Enum Description of an abstract class
Before we look at the specification, let’s look at the inheritance relationship of Enum classes to get a general idea
/** * This is the common Base class of all Java language enumeration types. * This is the common base class of all Java language enumeration types enums, including descriptions of the implicitly declared methods synthesized by the compiler, Can be * found in section 8.9 of <cite>The Java™ * For more information on enumerations, including a description of the implicit declaration method synthesized by the compiler, Note that when using an enumeration type as the type of a set * or as the type of the keys in a map, specialized and efficient * {@linkplain java.util.EnumSet set} and {@linkplain* Java.util. EnumMap map} implementations are available. * If you want to use set or map of enumeration type you can use EnumSet and EnumMap *@param <E> The enum type subclass
* @author Josh Bloch
* @author Neal Gafter
* @see Class#getEnumConstants()
* @see java.util.EnumSet
* @see java.util.EnumMap
* @since1.5 * /
public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable {... . }Copy the code
We can see that Enum implements the Comparable and Serializable interfaces, We have covered the Comparable interface in depth — the Comparable and Comparator can be used in dozens of different ways. We will also cover Serializable separately. Unlike the conventional inherited Serializable interface, the Enum abstract class has its own special implementation, which we will explain later
Common methods of Enum
Enum is the common base class for all Java language enumeration types (note that Enum is an abstract class). Here are the common methods:
The return type | Method names | Method statement |
---|---|---|
int |
compareTo(E o) |
Compares the order of this enumeration with the specified objects |
boolean |
equals(Object other) |
Returns true when the specified object is equal to this enumeration constant. |
Class<? > |
getDeclaringClass() |
Returns the Class object corresponding to the enumeration type of this enumeration constant |
String |
name() |
Returns the name of this enumeration constant to declare in its enumeration declaration |
int |
ordinal() |
Returns the ordinal of an enumeration constant (its position in the enumeration declaration, where the initial constant ordinal is zero) |
String |
toString() |
Returns the name of the enumeration constant contained in the declaration |
static<T extends Enum<T>> T |
static valueOf(Class<T> enumType, String name) |
Returns an enumeration constant of the specified enumeration type with the specified name. |
The ordinal method
The ordinal() method returns the order in which the enumeration variables are declared in the enumeration class, with indices starting at 0. If MONDAY is the first position on the date, then MONDAY’s ordinal is 0. If MONDAY’s position changes, the ordinal method returns the same value
Note that in most cases we should not use this method in the first place, because it is always unpredictable. Let’s test if this is the case. We find that the test case can run, which means that the return value of dateenm.monday.ordinal () is indeed 0
@Test
public void useEnumOrdinal(a) {
int ordinal=DateEnum.MONDAY.ordinal();
Assert.assertEquals(0,ordinal);
}
Copy the code
CompareTo method
The compareTo(E O) method compares the sizes of enumerations, noting that its internal implementation compares the ordinal value size of each enumeration.
@Test
public void useEnumCompareTo(a) {
int compare=DateEnum.MONDAY.compareTo(DateEnum.FRIDAY);
System.out.println(compare);
}
// Data result -4
Copy the code
MONDAY’s ordinal is 0, DateEnum.FRIDAY’s ordinal is 4, so isn’t that -4? Next, let’s look at the source code
/** * Compares this enum with the specified object for order. Returns a * negative integer, zero, Or a positive integer as this object is less * than, equal to, or greater than the specified object. Compares the current enumeration with the specified object, returns a negative number when the current object is less than, equal to, greater than, or the specified object. Constants are only comparable to other Enum constants of the same Enum type. * Enumeration constants can only be compared with other enumeration constants of the same type * the Natural order Implemented by this method is the order in which the constants are declared. * the natural order implemented by this method is the declared order of constants */
public final int compareTo(E o) { Enum<? > other = (Enum<? >)o; Enum<E> self =this;
if(self.getClass() ! = other.getClass() &&// optimizationself.getDeclaringClass() ! = other.getDeclaringClass())throw new ClassCastException();
return self.ordinal - other.ordinal;
}
Copy the code
Summary: 1. Compare the position (the position of the variable declaration). 2
Name method and toString method
The name() method is almost identical to toString() in that it is a string of output variables.
@Test
public void useEnumName(a) {
String name = DateEnum.MONDAY.name();
String toStr = DateEnum.MONDAY.toString();
System.out.println(name);
System.out.println(toStr);
}
// Output the result
MONDAY
MONDAY
Copy the code
The signature and implementation of these two methods are posted below. Let’s take a look. Some people say this is not nice, because there are two methods that can achieve the effect of obtaining the variable name
/** * Returns the name of this enum constant, exactly as declared in its enum declaration. * <b>Most programmers should use the {@link#toString} method in preference to this one, As the toString method may return a more user-friendly name.</b> * Programs should use toString instead of this method. Because the toString method returns values that are more friendly, This method is designed primarily for use in specialized situations where bros are on Getting the * exact name, which will not vary from release to release. Scenes that don't change from version to version *@return the name of this enum constant
*/
public final String name(a) {
return name;
}
/** * Returns the name of this enum constant, As contained in the declaration. * Return the name of This enumeration constant contained in the declaration * This method may be overridden, though it typically * isn't necessary or desirable. An enum type should override this * method when a more * This method may be overridden, although it is not necessary or desirable. If your program needs a more friendly return value, you can override this method *@return the name of this enum constant
*/
public String toString(a) {
return name;
}
Copy the code
This bottom, you know, these two are different, existence is reasonable, others will not design without reason! Being curious is always an excellent and noble quality. Because the name method is designed for this purpose, the name method is final, which means it cannot be overridden, so it guarantees that the return value of the name method will never change
Next, let’s rewrite the toString method to see the output above, which is our test case useEnumName
public enum DateEnum {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
@Override
public String toString(a) {
return this.getClass() + "."+ name(); }}Copy the code
@Test
public void useEnumName(a) {
String name = DateEnum.MONDAY.name();
String toStr = DateEnum.MONDAY.toString();
System.out.println(name);
System.out.println(toStr);
}
// Output the result
MONDAY
class datastructure.java.DateEnum.MONDAY
Copy the code
You can see that toString we can rewrite it to make the output more user-friendly
Compilers generate Values and ValueOf methods
Values () and valueOf(String name) are static methods generated by the compiler, so values() does not appear in the Enum class in the previous analysis, but valueOf() does appear. The compiler generates valueOf(), which requires only one name argument, while the static valueOf() method of Enum passes two methods. The compiler generates valueOf(), which calls valueOf() of Enum
To demonstrate what these two methods can do, let’s first look at values(). Because I overrode the toString method of DateEnum, I commented out the overridden toString method before demonstrating it, because values() returns an array, Well, we could probably guess seven, seven, seven, eight, but just to verify that, I’m going to print it out here
@Test
public void useEnumValues(a) {
System.out.println(Arrays.toString( DateEnum.MONDAY.values()));
System.out.println(Arrays.toString( DateEnum.values()));
}
// Output the result
[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
Copy the code
As you can see from the results, the values() method takes all the variables in the enumerated class and returns them as an array
We must also note here that since the values() method is a static method inserted by the compiler into the enumeration class (the resulting class), if we cast the enumeration instance up to Enum, the values() method will not be called because there is no values() method in the Enum class. The valueOf() method works the same way (note that it is a parameter).
Let’s take a look at the source code in the idle class
/** * Returns the enum constant of the specified enum type with the * specified name. The name must match exactly an identifier used * to declare an enum constant in this type. (Extraneous whitespace characters are not permitted.) * Returns an enumeration constant of the specified type and type, with the same name as when the enumeration type was declared (extra Spaces are not allowed) *@since1.5 * /
public static <T extends Enum<T>> T valueOf(Class
enumType, String name)
{
T result = enumType.enumConstantDirectory().get(name);
if(result ! =null)
return result;
if (name == null)
throw new NullPointerException("Name is null");
throw new IllegalArgumentException(
"No enum constant " + enumType.getCanonicalName() + "." + name);
}
Copy the code
As we know from the above comment, it simply returns the enumeration constant for the name we passed in, and that’s it. Now let’s look at how it works. You can see why there are toString methods and name methods. You can’t take the return valueOf toString as an argument to valueOf, let alone rewrite it
The toString method
@Test
public void useEnumvalueOf(a) {
Assert.assertEquals(DateEnum.MONDAY,DateEnum.MONDAY.valueOf(DateEnum.MONDAY.name()));
System.out.println( DateEnum.MONDAY.valueOf(DateEnum.MONDAY.name()));
System.out.println( DateEnum.valueOf(DateEnum.MONDAY.name()));
}
// Output the result
class datastructure.DateEnum.MONDAY
class datastructure.DateEnum.MONDAY
Copy the code
From the output, we can see that the test case runs past, that is, it returns the DateEnum.MONDAY enumeration constant. Next, we try calling the valueOf method in the abstract class, the one with two arguments
@Test
public void useEnumvalueOf2(a) {
Assert.assertEquals(DateEnum.MONDAY,DateEnum.MONDAY.valueOf(DateEnum.class,DateEnum.MONDAY.name()));
System.out.println( DateEnum.MONDAY.valueOf(DateEnum.class,DateEnum.MONDAY.name()));
System.out.println( DateEnum.valueOf(DateEnum.class,DateEnum.MONDAY.name()));
}
// Output the result
class datastructure.DateEnum.MONDAY
class datastructure.DateEnum.MONDAY
Copy the code
From the output, the effect is the same, that is, the compiler for us to generate the abstract class valueOf is to simplify the use of the Enum valueOf
getDeclaringClass
First let’s take a look at the source code for this method
Returns the Class object corresponding to this enum constant's enum type * Two enum constants E1 and E2 are of the same enum type if and only if * e1.getDeclaringClass() == E1.getdeclaringclass () == e2.getDeclaringClass(). * (The value returned by this method may differ from the one returned * by the {@linkObject#getClass} method for enum constants with * constant-specific class bodies.) * the return value of this method may not be the same as the return value of the getClass method called by an enumeration object *@return the Class object corresponding to this enum constant's
* enum type
*/
@SuppressWarnings("unchecked")
public final Class<E> getDeclaringClass(a) {
// Get the class object of the current objectClass<? > clazz = getClass();// Get the parent of the current object's class objectClass<? > zuper = clazz.getSuperclass();return (zuper == Enum.class) ? (Class<E>)clazz : (Class<E>)zuper;
}
Copy the code
Let’s take a look at a demo to help us understand this
@Test
public void useEnumClass(a) {
Class klass = DateEnum.MONDAY.getDeclaringClass();
System.out.println(klass);
Class blass = DateEnum.MONDAY.getClass();
System.out.println(blass);
System.out.println(blass);
System.out.println(klass==blass);
}
Copy the code
The output
class datastructure.java.DateEnum
class datastructure.java.DateEnum
class java.lang.Enum
true
Copy the code
We can see that the output of the getDeclaringClass method is the same as the.getClass method
As we mentioned above, when an enumeration instance is upcast to Enum type, the values() method is invalidated, making it impossible to fetch all of the enumeration instance variables at once
But because of the Class object, it is possible to get all of the enumeration instance variables at once, even without using values(). There are the following methods in the Class object:
The return type | Method names | Method statement |
---|---|---|
T[] |
getEnumConstants() |
Returns all elements of the enumerated type, or NULL if the Class object is not an enumerated type. |
boolean |
isEnum() |
Returns true if and only if the class is declared as an enumeration in source code |
So with the getEnumConstants() method, it’s equally easy to get all of the enumerated instance variables:
@Test
public void useClassGetEnumConstants(a) { Enum e = DateEnum.MONDAY; Class<? > klass = e.getDeclaringClass();if(klass.isEnum()) {
DateEnum[] constants = (DateEnum[]) klass.getEnumConstants();
System.out.println("constants1:"+Arrays.toString(constants));
}
DateEnum[] constants= DateEnum.MONDAY.values();
System.out.println("constants2:"+Arrays.toString(constants));
}
Copy the code
The output
constants1:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
constants2:[MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY]
Copy the code
As the code above shows, we can still get all of the enumeration instance constants at once through the getEnumConstants method of Enum’s class object, just as we can with the values method of an enumeration object
conclusion
- Benefits of enumerations: Constants can be organized together to manage typical application scenarios such as error codes, state machines, etc., which is easier to manage and maintain than using constants directly.
- The use of enumerations is simple, requiring only the enum keyword to declare
- The underlying principle of enumeration is that it inherits the Enum abstract class, and the compiler eventually compiles the enumeration into a plain Java class for use by the Java Virtual machine
- The variables declared in an enumeration are typed, that is, the enumeration type (which is also a normal Java class).