java基础之枚举类型(一)

enum基本特性

enum Shrubbery { GROUND, CRAWLING, HANGING }

public class EnumClass {

    public static void main(String[] args) {
        for(Shrubbery s : Shrubbery.values()) {
            System.out.println(s + " ordinal: " + s.ordinal());
            System.out.println(s.compareTo(Shrubbery.CRAWLING) + " ");
            System.out.println(s.equals(Shrubbery.CRAWLING) + " ");
            System.out.println(s == Shrubbery.CRAWLING);
            System.out.println(s.getDeclaringClass());
            System.out.println(s.name());
            System.out.println("----------------------");
        }
        // Produce an enum value from a string name:
        for(String s : "HANGING CRAWLING GROUND".split(" ")) {
            Shrubbery shrub = Enum.valueOf(Shrubbery.class, s);
            System.out.println(shrub);
        }
    }
}

输出结果为:

GROUND ordinal: 0
-1 
false 
false
class io.github.klink.Shrubbery
GROUND
----------------------
CRAWLING ordinal: 1
0 
true 
true
class io.github.klink.Shrubbery
CRAWLING
----------------------
HANGING ordinal: 2
1 
false 
false
class io.github.klink.Shrubbery
HANGING
----------------------
HANGING
CRAWLING
GROUND

从上面的例子,我们看到enum带有一些方法。实质上每个enum实例都会继承java.lang.Enum,诸如ordinal(),compareTo()方法都是在Enum中定义的。

java.lang.Enum

Enum继承了Comparable接口。并且实现了“自限制”。此外它还提供了一些常用的方法。

Comparable Interface

int compareTo(E o)
//Compares this enum with the specified object for order.


boolean equals(Object other)
//Returns true if the specified object is equal to this enum constant.

Class<E>    getDeclaringClass()
//Returns the Class object corresponding to this enum constant's enum type.

String  name()
//Returns the name of this enum constant, exactly as declared in its enum declaration.

int ordinal()
//Returns the ordinal of this enumeration constant (its position in its enum declaration, where the initial constant is assigned an ordinal of zero).

static <T extends Enum<T>> 
T   valueOf(Class<T> enumType, String name)
//Returns the enum constant of the specified enum type with the specified name.

向enum中添加method

既然enum继承自java.lang.Enum,所以enum定义的名称实质上是一个类。而enum内部的值我们可以将他们看作是该类的实例。

因此向enum中添加method与向普通的类中添加方法的步骤是一样的。

public enum OzWitch {
    //Instances must be defined first, before methods:
    WEST("Miss Gulch, aka the Wicked Witch of the West"),

    NORTH("Glinda, the Good Witch of the North"),

    EAST("Wicked Witch of the East, wearer of the Ruby " +
            "Slippers, crushed by Dorothy’s house"),

    SOUTH("Good by inference, but missing");

    private String description;

    //Constructor must be package or private access:
    private OzWitch(String description) {
        this.description = description;
    }

    public String getDescription() { return description; }

    public static void main(String[] args) {
        for(OzWitch witch : OzWitch.values())
            System.out.println(witch + ": " + witch.getDescription());
    }
}

输出结果为:

WEST: Miss Gulch, aka the Wicked Witch of the West
NORTH: Glinda, the Good Witch of the North
EAST: Wicked Witch of the East, wearer of the Ruby Slippers, crushed by Dorothy’s house
SOUTH: Good by inference, but missing

enum除了添加一些方法外,还可以对java.lang.Enum中的一些方法进行override。

由于enum继承了java.lang.Enum类,所以enum无法再继承其他的类。但是enum可以实现接口来扩展enum的功能。

values()方法从何而来

在刚开始的示例中,我们使用到了values()方法,但是该方法在java.lang.Enum中并没有定义。那么这个方法是从何而来的呢?

import java.lang.reflect.*;

import java.lang.reflect.*;
import java.util.*;

enum Explore { HERE, THERE }

public class Reflection {
    public static Set<String> analyze(Class<?> enumClass) {
        System.out.println("----- Analyzing " + enumClass + " -----");

        System.out.println("Interfaces:");

        for(Type t : enumClass.getGenericInterfaces())
            System.out.println(t);
        System.out.println("Base: " + enumClass.getSuperclass());
        System.out.println("Methods: ");
        Set<String> methods = new TreeSet<String>();

        for(Method m : enumClass.getMethods())
            methods.add(m.getName());
        System.out.println(methods);
        return methods;
    }

    public static void main(String[] args) {
        Set<String> exploreMethods = analyze(Explore.class);
        Set<String> enumMethods = analyze(Enum.class);
        System.out.println("Explore.containsAll(Enum)? " +
                exploreMethods.containsAll(enumMethods));
        System.out.println("Explore.removeAll(Enum): ");
        exploreMethods.removeAll(enumMethods);
        System.out.println(exploreMethods);

    }
}

输出结果为:

Base: class java.lang.Enum
Interfaces:
Base: class java.lang.Enum
Methods: 
[compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, values, wait]
----- Analyzing class java.lang.Enum -----
Interfaces:
java.lang.Comparable<E>
interface java.io.Serializable
Base: class java.lang.Object
Methods: 
[compareTo, equals, getClass, getDeclaringClass, hashCode, name, notify, notifyAll, ordinal, toString, valueOf, wait]
Explore.containsAll(Enum)? true
Explore.removeAll(Enum): 
[values]

从上面实例程序的输出,可以看出values()的方法是在Explore类创建的过程中由java compiler 自动生成的一个方法。
反编译之后,Explore类如下:

final class Explore extends java.lang.Enum{
public static final Explore HERE;
public static final Explore THERE;
public static final Explore[] values();
public static Explore valueOf(java.lang.String);
static {};
}

Enum的容器类库

由于Enum是一个特殊的数据类型,所以在容器类库中,java为它实现了一些特有的类。

EnumSet

public abstract class EnumSet<E extends Enum<E>>

EnumSet是一个abstract class,EnumSet内部存放的数据必须是继承自Enum的数据。另外由于它继承自java.util.AbstractSet,所以它具有Set的所有功能。

此外EnumSet还提供了一些特有的方法:

static <E extends Enum<E>> 
EnumSet<E>  allOf(Class<E> elementType)
//Creates an enum set containing all of the elements in the specified element type.

static <E extends Enum<E>> 
EnumSet<E>  complementOf(EnumSet<E> s)
//Creates an enum set with the same element type as the specified enum set, initially containing all the elements of this type that are not contained in the specified set.

static <E extends Enum<E>> 
EnumSet<E>  copyOf(Collection<E> c)
//Creates an enum set initialized from the specified collection.

static <E extends Enum<E>> 
EnumSet<E>  copyOf(EnumSet<E> s)
//Creates an enum set with the same element type as the specified enum set, initially containing the same elements (if any).

static <E extends Enum<E>> 
EnumSet<E>  noneOf(Class<E> elementType)
//Creates an empty enum set with the specified element type.

static <E extends Enum<E>> 
EnumSet<E>  of(E e)
//Creates an enum set initially containing the specified element.

static <E extends Enum<E>> 
EnumSet<E>  of(E first, E... rest)
//Creates an enum set initially containing the specified elements.

static <E extends Enum<E>> 
EnumSet<E>  of(E e1, E e2)
//Creates an enum set initially containing the specified elements.

static <E extends Enum<E>> 
EnumSet<E>  of(E e1, E e2, E e3)
//Creates an enum set initially containing the specified elements.

static <E extends Enum<E>> 
EnumSet<E>  of(E e1, E e2, E e3, E e4)
//Creates an enum set initially containing the specified elements.

static <E extends Enum<E>> 
EnumSet<E>  of(E e1, E e2, E e3, E e4, E e5)
//Creates an enum set initially containing the specified elements.

static <E extends Enum<E>> 
EnumSet<E>  range(E from, E to)
//Creates an enum set initially containing all of the elements in the range defined by the two specified endpoints.

既然EnumSet是一个Abstract类,那么在使用EnumSet的过程中,肯定是需要实例化的类来进行具体操作的。java.util内部实现了两个EnumSet的子类,分别是:RegularEnumSet和JumboEnumSet。

  • RegularEnumSet和JumboEnumSet的区别在于,当EnumSet中存储的数据少于64个时,EnumSet使用的是RegularEnumSet,RegularEnumSet内部定义了一个long型的变量来存储所有的EnumSet数据。而当EnumSet中存储的数据多于64个时,RegularEnumSet无法存储这些多数据,EnumSet内部就会实例化一个JumboEnumSet,JumboEnumSet内部定义了一个long[],所以当数据较多时,EnumSet会自动切换成JumboEnumSet。一般当我们想要实例化一个EnumSet时可以调用方法noneOf()

  • 出于这么设计的目的是因为,noneOf(Class elementType)给定的参数是一个Enum的Class。因为Enum中有多少实例是固定的。在调用的过程是就能知道该EnumSet的最大长度是多少。所以当我们使用add()方法时只需要改变Long型变量的一个bit就可以了。

    import java.util.*;

    enum AlarmPoints {

    STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,
    OFFICE4, BATHROOM, UTILITY, KITCHEN
    

    }

    public class EnumSets {

    public static void main(String[] args) {
        EnumSet<AlarmPoints> points =
                EnumSet.noneOf(AlarmPoints.class); // Empty set
        points.add(AlarmPoints.BATHROOM);
        System.out.println(points);
    
        points.addAll(EnumSet.of(AlarmPoints.STAIR1, AlarmPoints.STAIR2, AlarmPoints.KITCHEN));
        System.out.println(points);
    
        points = EnumSet.allOf(AlarmPoints.class);
        points.removeAll(EnumSet.of(AlarmPoints.STAIR1, AlarmPoints.STAIR2, AlarmPoints.KITCHEN));
        System.out.println(points);
    
        points.removeAll(EnumSet.range(AlarmPoints.OFFICE1, AlarmPoints.OFFICE4));
        System.out.println(points);
        points = EnumSet.complementOf(points);
        System.out.println(points);
    }
    

    }

输出结果为:

[BATHROOM]
[STAIR1, STAIR2, BATHROOM, KITCHEN]
[LOBBY, OFFICE1, OFFICE2, OFFICE3, OFFICE4, BATHROOM, UTILITY]
[LOBBY, BATHROOM, UTILITY]
[STAIR1, STAIR2, OFFICE1, OFFICE2, OFFICE3, OFFICE4, KITCHEN]

EnumMap

public class EnumMap<K extends Enum<K>,V>

EnumMap是一个特殊的Map,它继承自 AbstractMap,它的Key继承了Enum类。

EnumMap有3个构造函数。

EnumMap(Class<K> keyType)
//Creates an empty enum map with the specified key type.
EnumMap(EnumMap<K,? extends V> m)
//Creates an enum map with the same key type as the specified enum map, initially containing the same mappings (if any).
EnumMap(Map<K,? extends V> m)
//Creates an enum map initialized from the specified map.

示例:

import java.util.*;

enum AlarmPoints {
    STAIR1, STAIR2, LOBBY, OFFICE1, OFFICE2, OFFICE3,
    OFFICE4, BATHROOM, UTILITY, KITCHEN
}

interface Command { void action(); }

public class EnumMaps {

    public static void main(String[] args) {
        EnumMap<AlarmPoints,Command> em =
                new EnumMap<AlarmPoints,Command>(AlarmPoints.class);
        em.put(AlarmPoints.KITCHEN, new Command() {
            public void action() { System.out.println("Kitchen fire!"); }
        });
        em.put(AlarmPoints.BATHROOM, new Command() {
            public void action() { System.out.println("Bathroom alert!"); }
        });

        for(Map.Entry<AlarmPoints,Command> e : em.entrySet()) {
            System.out.println(e.getKey() + ": ");
            e.getValue().action();
        }
        try { // If there’s no value for a particular key:
            em.get(AlarmPoints.UTILITY).action();
        } catch(Exception e) {
            System.out.println(e);
        }
    }
}

输出结果为:

java.lang.NullPointerException
Bathroom alert!
KITCHEN: 
Kitchen fire!
java.lang.NullPointerException

你可能感兴趣的:(enum,enumMap,enumset)