枚举类也是一个类,继承于java.lang.Enum类。
public enum MyEnum{
NOT("hot"),MIDE("mide"),MEDIUM("medium"),HOT("hot"),FLAMING("flaming");
private String des;
privateMyEnum(String des){
this.des=des;
}
}
通过javap -verbose MyEnum.class查看MyEnum的字节码:
Classfile /C:/Users/Administrator/Desktop/MyEnum.class
Last modified 2019-3-7; size 1080 bytes
MD5 checksum 3b829a7774431148e162203408665658
Compiled from "MyEnum.java"
public final class MyEnum extends java.lang.Enum //final Enum类型不能被继承
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_FINAL, ACC_SUPER, ACC_ENUM
Constant pool:
#1 = Fieldref #4.#49 // MyEnum.$VALUES:[LMyEnum;
#2 = Methodref #50.#51 // "[LMyEnum;".clone:()Ljava/lang/O
ct;
#3 = Class #33 // "[LMyEnum;"
#4 = Class #52 // MyEnum
#5 = Methodref #23.#53 // java/lang/Enum.valueOf:(Ljava/la
Class;Ljava/lang/String;)Ljava/lang/Enum;
#6 = Methodref #23.#54 // java/lang/Enum."":(Ljava/l
/String;I)V
#7 = Fieldref #4.#55 // MyEnum.des:Ljava/lang/String;
#8 = String #24 // NOT
#9 = String #56 // hot
#10 = Methodref #4.#57 // MyEnum."":(Ljava/lang/Stri
ILjava/lang/String;)V
#11 = Fieldref #4.#58 // MyEnum.NOT:LMyEnum;
#12 = String #26 // MIDE
#13 = String #59 // mide
#14 = Fieldref #4.#60 // MyEnum.MIDE:LMyEnum;
#15 = String #27 // MEDIUM
#16 = String #61 // medium
#17 = Fieldref #4.#62 // MyEnum.MEDIUM:LMyEnum;
#18 = String #28 // HOT
#19 = Fieldref #4.#63 // MyEnum.HOT:LMyEnum;
#20 = String #29 // FLAMING
#21 = String #64 // flaming
#22 = Fieldref #4.#65 // MyEnum.FLAMING:LMyEnum;
#23 = Class #66 // java/lang/Enum
#24 = Utf8 NOT
#25 = Utf8 LMyEnum;
#26 = Utf8 MIDE
#27 = Utf8 MEDIUM
#28 = Utf8 HOT
#29 = Utf8 FLAMING
#30 = Utf8 des
#31 = Utf8 Ljava/lang/String;
#32 = Utf8 $VALUES
#33 = Utf8 [LMyEnum;
#34 = Utf8 values
#35 = Utf8 ()[LMyEnum;
#36 = Utf8 Code
#37 = Utf8 LineNumberTable
#38 = Utf8 valueOf
#39 = Utf8 (Ljava/lang/String;)LMyEnum;
#40 = Utf8
#41 = Utf8 (Ljava/lang/String;ILjava/lang/String;)V
#42 = Utf8 Signature
#43 = Utf8 (Ljava/lang/String;)V
#44 = Utf8
#45 = Utf8 ()V
#46 = Utf8 Ljava/lang/Enum;
#47 = Utf8 SourceFile
#48 = Utf8 MyEnum.java
#49 = NameAndType #32:#33 // $VALUES:[LMyEnum;
#50 = Class #33 // "[LMyEnum;"
#51 = NameAndType #67:#68 // clone:()Ljava/lang/Object;
#52 = Utf8 MyEnum
#53 = NameAndType #38:#69 // valueOf:(Ljava/lang/Class;Ljava/
g/String;)Ljava/lang/Enum;
#54 = NameAndType #40:#70 // "":(Ljava/lang/String;I)V
#55 = NameAndType #30:#31 // des:Ljava/lang/String;
#56 = Utf8 hot
#57 = NameAndType #40:#41 // "":(Ljava/lang/String;ILja
lang/String;)V
#58 = NameAndType #24:#25 // NOT:LMyEnum;
#59 = Utf8 mide
#60 = NameAndType #26:#25 // MIDE:LMyEnum;
#61 = Utf8 medium
#62 = NameAndType #27:#25 // MEDIUM:LMyEnum;
#63 = NameAndType #28:#25 // HOT:LMyEnum;
#64 = Utf8 flaming
#65 = NameAndType #29:#25 // FLAMING:LMyEnum;
#66 = Utf8 java/lang/Enum
#67 = Utf8 clone
#68 = Utf8 ()Ljava/lang/Object;
#69 = Utf8 (Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/En
#70 = Utf8 (Ljava/lang/String;I)V
{
public static final MyEnum NOT;
descriptor: LMyEnum;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM //各个枚举类的实例
public static final MyEnum MIDE;
descriptor: LMyEnum;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final MyEnum MEDIUM;
descriptor: LMyEnum;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final MyEnum HOT;
descriptor: LMyEnum;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static final MyEnum FLAMING;
descriptor: LMyEnum;
flags: ACC_PUBLIC, ACC_STATIC, ACC_FINAL, ACC_ENUM
public static MyEnum[] values();
descriptor: ()[LMyEnum;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: getstatic #1 // Field $VALUES:[LMyEnum;
3: invokevirtual #2 // Method "[LMyEnum;".clone:()L
a/lang/Object;
6: checkcast #3 // class "[LMyEnum;"
9: areturn
LineNumberTable:
line 1: 0
public static MyEnum valueOf(java.lang.String);
descriptor: (Ljava/lang/String;)LMyEnum;
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: ldc #4 // class MyEnum
2: aload_0
3: invokestatic #5 // Method java/lang/Enum.valueO
Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #4 // class MyEnum
9: areturn
LineNumberTable:
line 1: 0
static {}; //静态代码块,用于初始化个枚举类对象
descriptor: ()V
flags: ACC_STATIC
Code:
stack=5, locals=0, args_size=0
0: new #4 // class MyEnum
3: dup
4: ldc #8 // String NOT
6: iconst_0
7: ldc #9 // String hot
9: invokespecial #10 // Method "":(Ljava/lang/
ing;ILjava/lang/String;)V
12: putstatic #11 // Field NOT:LMyEnum;
15: new #4 // class MyEnum
18: dup
19: ldc #12 // String MIDE
21: iconst_1
22: ldc #13 // String mide
24: invokespecial #10 // Method "":(Ljava/lang/
ing;ILjava/lang/String;)V
27: putstatic #14 // Field MIDE:LMyEnum;
30: new #4 // class MyEnum
33: dup
34: ldc #15 // String MEDIUM
36: iconst_2
37: ldc #16 // String medium
39: invokespecial #10 // Method "":(Ljava/lang/
ing;ILjava/lang/String;)V
42: putstatic #17 // Field MEDIUM:LMyEnum;
45: new #4 // class MyEnum
48: dup
49: ldc #18 // String HOT
51: iconst_3
52: ldc #9 // String hot
54: invokespecial #10 // Method "":(Ljava/lang/
ing;ILjava/lang/String;)V
57: putstatic #19 // Field HOT:LMyEnum;
60: new #4 // class MyEnum
63: dup
64: ldc #20 // String FLAMING
66: iconst_4
67: ldc #21 // String flaming
69: invokespecial #10 // Method "":(Ljava/lang/
ing;ILjava/lang/String;)V
72: putstatic #22 // Field FLAMING:LMyEnum;
75: iconst_5
76: anewarray #4 // class MyEnum
79: dup
80: iconst_0
81: getstatic #11 // Field NOT:LMyEnum;
84: aastore
85: dup
86: iconst_1
87: getstatic #14 // Field MIDE:LMyEnum;
90: aastore
91: dup
92: iconst_2
93: getstatic #17 // Field MEDIUM:LMyEnum;
96: aastore
97: dup
98: iconst_3
99: getstatic #19 // Field HOT:LMyEnum;
102: aastore
103: dup
104: iconst_4
105: getstatic #22 // Field FLAMING:LMyEnum;
108: aastore
109: putstatic #1 // Field $VALUES:[LMyEnum;
112: return
LineNumberTable:
line 2: 0
line 1: 75
}
Signature: #46 // Ljava/lang/Enum;
SourceFile: "MyEnum.java"
可以看到上边MyEnum的枚举通过编译器编译后就变成MyEnum类并继承于Enum类,MyEnum类里面有NOT,MEDIUM等对象应用,都是public static final修饰,有一个static代码块实例化各种枚举对象。
//: enumerated/TrafficLight.java
// Enums in switch statements.
import static net.mindview.util.Print.*;
// Define an enum type:
enum Signal { GREEN, YELLOW, RED, }
public class TrafficLight {
Signal color = Signal.RED;
public void change() {
switch(color) {
// Note that you don't have to say Signal.RED
// in the case statement:
case RED: color = Signal.GREEN;
break;
case GREEN: color = Signal.YELLOW;
break;
case YELLOW: color = Signal.RED;
break;
}
}
public String toString() {
return "The traffic light is " + color;
}
public static void main(String[] args) {
TrafficLight t = new TrafficLight();
for(int i = 0; i < 7; i++) {
print(t);
t.change();
}
}
}
这个方法由编译器自动生成,返回所有枚举对象。Class类的getEnumConstans()也可以放回这个Class类的所有对象,没有就返回null。
package enumerated.menu;
public interface Food {
enum Appetizer implements Food {
SALAD, SOUP, SPRING_ROLLS;
}
enum MainCourse implements Food {
LASAGNE, BURRITO, PAD_THAI,
LENTILS, HUMMOUS, VINDALOO;
}
enum Dessert implements Food {
TIRAMISU, GELATO, BLACK_FOREST_CAKE,
FRUIT, CREME_CARAMEL;
}
enum Coffee implements Food {
BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
LATTE, CAPPUCCINO, TEA, HERB_TEA;
}
} ///:~
可以用枚举的枚举数据简化操作
public enum Course {
APPETIZER(Food.Appetizer.class),
MAINCOURSE(Food.MainCourse.class),
DESSERT(Food.Dessert.class),
COFFEE(Food.Coffee.class);
private Food[] values;
private Course(Class extends Food> kind) {
values = kind.getEnumConstants();
}
public Food randomSelection() {
return Enums.random(values);
}
} ///:~
EnumSet是为Enum类专门设计的一个集合类。内部是通过一个long型字段或者一个long型数组实现的
public abstract class EnumSet> extends AbstractSet
implements Cloneable, java.io.Serializable
{
/**
* The class of all the elements of this set.
*/
final Class elementType;//集合的枚举类型
/**
* All of the values comprising T. (Cached for performance.)
*/
final Enum>[] universe;
private static Enum>[] ZERO_LENGTH_ENUM_ARRAY = new Enum>[0];
EnumSet(ClasselementType, Enum>[] universe) {
this.elementType = elementType;
this.universe = universe;
}
/**
空的枚举集合
* Creates an empty enum set with the specified element type.
*
* @param The class of the elements in the set
* @param elementType the class object of the element type for this enum
* set
* @return An empty enum set of the specified type.
* @throws NullPointerException if elementType is null
*/
public static > EnumSet noneOf(Class elementType) {
Enum>[] universe = getUniverse(elementType);
if (universe == null)
throw new ClassCastException(elementType + " not an enum");
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
/**创建一个包含所有枚举对象的枚举集合
* Creates an enum set containing all of the elements in the specified
* element type.
*
* @param The class of the elements in the set
* @param elementType the class object of the element type for this enum
* set
* @return An enum set containing all the elements in the specified type.
* @throws NullPointerException if elementType is null
*/
public static > EnumSet allOf(Class elementType) {
EnumSet result = noneOf(elementType);
result.addAll();
return result;
}
/**
* Adds all of the elements from the appropriate enum type to this enum
* set, which is empty prior to the call.
*/
abstract void addAll();
/**
* Creates an enum set with the same element type as the specified enum
* set, initially containing the same elements (if any).
*
* @param The class of the elements in the set
* @param s the enum set from which to initialize this enum set
* @return A copy of the specified enum set.
* @throws NullPointerException if s is null
*/
public static > EnumSet copyOf(EnumSet s) {
return s.clone();
}
/**
复制集合
* Creates an enum set initialized from the specified collection. If
* the specified collection is an EnumSet instance, this static
* factory method behaves identically to {@link #copyOf(EnumSet)}.
* Otherwise, the specified collection must contain at least one element
* (in order to determine the new enum set's element type).
*
* @param The class of the elements in the collection
* @param c the collection from which to initialize this enum set
* @return An enum set initialized from the given collection.
* @throws IllegalArgumentException if c is not an
* EnumSet instance and contains no elements
* @throws NullPointerException if c is null
*/
public static > EnumSet copyOf(Collection c) {
if (c instanceof EnumSet) {
return ((EnumSet)c).clone();
} else {
if (c.isEmpty())
throw new IllegalArgumentException("Collection is empty");
Iterator i = c.iterator();
E first = i.next();
EnumSet result = EnumSet.of(first);
while (i.hasNext())
result.add(i.next());
return result;
}
}
/**
* 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.
*
* @param The class of the elements in the enum set
* @param s the enum set from whose complement to initialize this enum set
* @return The complement of the specified set in this set
* @throws NullPointerException if s is null
*/
public static > EnumSet complementOf(EnumSet s) {
EnumSet result = copyOf(s);
result.complement();
return result;
}
/**
* Creates an enum set initially containing the specified element.
*
* Overloadings of this method exist to initialize an enum set with
* one through five elements. A sixth overloading is provided that
* uses the varargs feature. This overloading may be used to create
* an enum set initially containing an arbitrary number of elements, but
* is likely to run slower than the overloadings that do not use varargs.
*
* @param The class of the specified element and of the set
* @param e the element that this set is to contain initially
* @throws NullPointerException if e is null
* @return an enum set initially containing the specified element
*/
public static > EnumSet of(E e) {
EnumSet result = noneOf(e.getDeclaringClass());
result.add(e);
return result;
}
/**
* Creates an enum set initially containing the specified elements.
*
* Overloadings of this method exist to initialize an enum set with
* one through five elements. A sixth overloading is provided that
* uses the varargs feature. This overloading may be used to create
* an enum set initially containing an arbitrary number of elements, but
* is likely to run slower than the overloadings that do not use varargs.
*
* @param The class of the parameter elements and of the set
* @param e1 an element that this set is to contain initially
* @param e2 another element that this set is to contain initially
* @throws NullPointerException if any parameters are null
* @return an enum set initially containing the specified elements
*/
public static > EnumSet of(E e1, E e2) {
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
return result;
}
/**
* Creates an enum set initially containing the specified elements.
*
* Overloadings of this method exist to initialize an enum set with
* one through five elements. A sixth overloading is provided that
* uses the varargs feature. This overloading may be used to create
* an enum set initially containing an arbitrary number of elements, but
* is likely to run slower than the overloadings that do not use varargs.
*
* @param The class of the parameter elements and of the set
* @param e1 an element that this set is to contain initially
* @param e2 another element that this set is to contain initially
* @param e3 another element that this set is to contain initially
* @throws NullPointerException if any parameters are null
* @return an enum set initially containing the specified elements
*/
public static > EnumSet of(E e1, E e2, E e3) {
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
return result;
}
/**
* Creates an enum set initially containing the specified elements.
*
* Overloadings of this method exist to initialize an enum set with
* one through five elements. A sixth overloading is provided that
* uses the varargs feature. This overloading may be used to create
* an enum set initially containing an arbitrary number of elements, but
* is likely to run slower than the overloadings that do not use varargs.
*
* @param The class of the parameter elements and of the set
* @param e1 an element that this set is to contain initially
* @param e2 another element that this set is to contain initially
* @param e3 another element that this set is to contain initially
* @param e4 another element that this set is to contain initially
* @throws NullPointerException if any parameters are null
* @return an enum set initially containing the specified elements
*/
public static > EnumSet of(E e1, E e2, E e3, E e4) {
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
return result;
}
/**
* Creates an enum set initially containing the specified elements.
*
* Overloadings of this method exist to initialize an enum set with
* one through five elements. A sixth overloading is provided that
* uses the varargs feature. This overloading may be used to create
* an enum set initially containing an arbitrary number of elements, but
* is likely to run slower than the overloadings that do not use varargs.
*
* @param The class of the parameter elements and of the set
* @param e1 an element that this set is to contain initially
* @param e2 another element that this set is to contain initially
* @param e3 another element that this set is to contain initially
* @param e4 another element that this set is to contain initially
* @param e5 another element that this set is to contain initially
* @throws NullPointerException if any parameters are null
* @return an enum set initially containing the specified elements
*/
public static > EnumSet of(E e1, E e2, E e3, E e4,
E e5)
{
EnumSet result = noneOf(e1.getDeclaringClass());
result.add(e1);
result.add(e2);
result.add(e3);
result.add(e4);
result.add(e5);
return result;
}
/**
* Creates an enum set initially containing the specified elements.
* This factory, whose parameter list uses the varargs feature, may
* be used to create an enum set initially containing an arbitrary
* number of elements, but it is likely to run slower than the overloadings
* that do not use varargs.
*
* @param The class of the parameter elements and of the set
* @param first an element that the set is to contain initially
* @param rest the remaining elements the set is to contain initially
* @throws NullPointerException if any of the specified elements are null,
* or if rest is null
* @return an enum set initially containing the specified elements
*/
@SafeVarargs
public static > EnumSet of(E first, E... rest) {
EnumSet result = noneOf(first.getDeclaringClass());
result.add(first);
for (E e : rest)
result.add(e);
return result;
}
/**
* Creates an enum set initially containing all of the elements in the
* range defined by the two specified endpoints. The returned set will
* contain the endpoints themselves, which may be identical but must not
* be out of order.
*
* @param The class of the parameter elements and of the set
* @param from the first element in the range
* @param to the last element in the range
* @throws NullPointerException if {@code from} or {@code to} are null
* @throws IllegalArgumentException if {@code from.compareTo(to) > 0}
* @return an enum set initially containing all of the elements in the
* range defined by the two specified endpoints
*/
public static > EnumSet range(E from, E to) {
if (from.compareTo(to) > 0)
throw new IllegalArgumentException(from + " > " + to);
EnumSet result = noneOf(from.getDeclaringClass());
result.addRange(from, to);
return result;
}
/**
* Adds the specified range to this enum set, which is empty prior
* to the call.
*/
abstract void addRange(E from, E to);
/**
* Returns a copy of this set.
*
* @return a copy of this set
*/
@SuppressWarnings("unchecked")
public EnumSet clone() {
try {
return (EnumSet) super.clone();
} catch(CloneNotSupportedException e) {
throw new AssertionError(e);
}
}
/**
* Complements the contents of this enum set.
*/
abstract void complement();
/**
* Throws an exception if e is not of the correct type for this enum set.
*/
final void typeCheck(E e) {
Class> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
throw new ClassCastException(eClass + " != " + elementType);
}
/**
* Returns all of the values comprising E.
* The result is uncloned, cached, and shared by all callers.
*/
private static > E[] getUniverse(Class elementType) {
return SharedSecrets.getJavaLangAccess()
.getEnumConstantsShared(elementType);
}
/**
* This class is used to serialize all EnumSet instances, regardless of
* implementation type. It captures their "logical contents" and they
* are reconstructed using public static factories. This is necessary
* to ensure that the existence of a particular implementation type is
* an implementation detail.
*
* @serial include
*/
private static class SerializationProxy >
implements java.io.Serializable
{
/**
* The element type of this enum set.
*
* @serial
*/
private final Class elementType;
/**
* The elements contained in this enum set.
*
* @serial
*/
private final Enum>[] elements;
SerializationProxy(EnumSet set) {
elementType = set.elementType;
elements = set.toArray(ZERO_LENGTH_ENUM_ARRAY);
}
// instead of cast to E, we should perhaps use elementType.cast()
// to avoid injection of forged stream, but it will slow the implementation
@SuppressWarnings("unchecked")
private Object readResolve() {
EnumSet result = EnumSet.noneOf(elementType);
for (Enum> e : elements)
result.add((E)e);
return result;
}
private static final long serialVersionUID = 362491234563181265L;
}
Object writeReplace() {
return new SerializationProxy<>(this);
}
// readObject method for the serialization proxy pattern
// See Effective Java, Second Ed., Item 78.
private void readObject(java.io.ObjectInputStream stream)
throws java.io.InvalidObjectException {
throw new java.io.InvalidObjectException("Proxy required");
}
}
实现类:RegularEnumSet(枚举对象不超过64个)
class RegularEnumSet> extends EnumSet {
private static final long serialVersionUID = 3411599620347842686L;
/**
* Bit vector representation of this set. The 2^k bit indicates the
* presence of universe[k] in this set.
*/
private long elements = 0L;//代表一个集合,2^k代表值为k的枚举对象存在在这个集合
RegularEnumSet(ClasselementType, Enum>[] universe) {
super(elementType, universe);
}
void addRange(E from, E to) {
elements = (-1L >>> (from.ordinal() - to.ordinal() - 1)) << from.ordinal();
}
void addAll() {
if (universe.length != 0)
elements = -1L >>> -universe.length;
}
void complement() {
if (universe.length != 0) {
elements = ~elements;
elements &= -1L >>> -universe.length; // Mask unused bits
}
}
/**
* Returns an iterator over the elements contained in this set. The
* iterator traverses the elements in their natural order (which is
* the order in which the enum constants are declared). The returned
* Iterator is a "snapshot" iterator that will never throw {@link
* ConcurrentModificationException}; the elements are traversed as they
* existed when this call was invoked.
*
* @return an iterator over the elements contained in this set
*/
public Iterator iterator() {
return new EnumSetIterator<>();
}
private class EnumSetIterator> implements Iterator {
/**
* A bit vector representing the elements in the set not yet
* returned by this iterator.
*/
long unseen;
/**
* The bit representing the last element returned by this iterator
* but not removed, or zero if no such element exists.
*/
long lastReturned = 0;
EnumSetIterator() {
unseen = elements;
}
public boolean hasNext() {
return unseen != 0;
}
@SuppressWarnings("unchecked")
public E next() {
if (unseen == 0)
throw new NoSuchElementException();
lastReturned = unseen & -unseen;
unseen -= lastReturned;
return (E) universe[Long.numberOfTrailingZeros(lastReturned)];
}
public void remove() {
if (lastReturned == 0)
throw new IllegalStateException();
elements &= ~lastReturned;
lastReturned = 0;
}
}
/**
* Returns the number of elements in this set.
*
* @return the number of elements in this set
*/
public int size() {
return Long.bitCount(elements);
}
/**
* Returns true if this set contains no elements.
*
* @return true if this set contains no elements
*/
public boolean isEmpty() {
return elements == 0;
}
/**
* Returns true if this set contains the specified element.
*
* @param e element to be checked for containment in this collection
* @return true if this set contains the specified element
*/
public boolean contains(Object e) {
if (e == null)
return false;
Class> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
return false;
return (elements & (1L << ((Enum>)e).ordinal())) != 0;
}
// Modification Operations
/**
* Adds the specified element to this set if it is not already present.
*
* @param e element to be added to this set
* @return true if the set changed as a result of the call
*
* @throws NullPointerException if e is null
*/
public boolean add(E e) {
typeCheck(e);
long oldElements = elements;
elements |= (1L << ((Enum>)e).ordinal());
return elements != oldElements;
}
/**
* Removes the specified element from this set if it is present.
*
* @param e element to be removed from this set, if present
* @return true if the set contained the specified element
*/
public boolean remove(Object e) {
if (e == null)
return false;
Class> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
return false;
long oldElements = elements;
elements &= ~(1L << ((Enum>)e).ordinal());
return elements != oldElements;
}
// Bulk Operations
/**
* Returns true if this set contains all of the elements
* in the specified collection.
*
* @param c collection to be checked for containment in this set
* @return true if this set contains all of the elements
* in the specified collection
* @throws NullPointerException if the specified collection is null
*/
public boolean containsAll(Collection> c) {
if (!(c instanceof RegularEnumSet))
return super.containsAll(c);
RegularEnumSet> es = (RegularEnumSet>)c;
if (es.elementType != elementType)
return es.isEmpty();
return (es.elements & ~elements) == 0;
}
/**
* Adds all of the elements in the specified collection to this set.
*
* @param c collection whose elements are to be added to this set
* @return true if this set changed as a result of the call
* @throws NullPointerException if the specified collection or any
* of its elements are null
*/
public boolean addAll(Collection extends E> c) {
if (!(c instanceof RegularEnumSet))
return super.addAll(c);
RegularEnumSet> es = (RegularEnumSet>)c;
if (es.elementType != elementType) {
if (es.isEmpty())
return false;
else
throw new ClassCastException(
es.elementType + " != " + elementType);
}
long oldElements = elements;
elements |= es.elements;
return elements != oldElements;
}
/**
* Removes from this set all of its elements that are contained in
* the specified collection.
*
* @param c elements to be removed from this set
* @return true if this set changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
public boolean removeAll(Collection> c) {
if (!(c instanceof RegularEnumSet))
return super.removeAll(c);
RegularEnumSet> es = (RegularEnumSet>)c;
if (es.elementType != elementType)
return false;
long oldElements = elements;
elements &= ~es.elements;
return elements != oldElements;
}
/**
* Retains only the elements in this set that are contained in the
* specified collection.
*
* @param c elements to be retained in this set
* @return true if this set changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
public boolean retainAll(Collection> c) {
if (!(c instanceof RegularEnumSet))
return super.retainAll(c);
RegularEnumSet> es = (RegularEnumSet>)c;
if (es.elementType != elementType) {
boolean changed = (elements != 0);
elements = 0;
return changed;
}
long oldElements = elements;
elements &= es.elements;
return elements != oldElements;
}
/**
* Removes all of the elements from this set.
*/
public void clear() {
elements = 0;
}
/**
* Compares the specified object with this set for equality. Returns
* true if the given object is also a set, the two sets have
* the same size, and every member of the given set is contained in
* this set.
*
* @param o object to be compared for equality with this set
* @return true if the specified object is equal to this set
*/
public boolean equals(Object o) {
if (!(o instanceof RegularEnumSet))
return super.equals(o);
RegularEnumSet> es = (RegularEnumSet>)o;
if (es.elementType != elementType)
return elements == 0 && es.elements == 0;
return es.elements == elements;
}
}
JumboEnumSet(枚举对象可以超过64个)
class JumboEnumSet> extends EnumSet {
private static final long serialVersionUID = 334349849919042784L;
/**
在第j个元素的第i位,代表着值为64*j+i的枚举在集合
* Bit vector representation of this set. The ith bit of the jth
* element of this array represents the presence of universe[64*j +i]
* in this set.
*/
private long elements[];
// Redundant - maintained for performance
private int size = 0;
JumboEnumSet(ClasselementType, Enum>[] universe) {
super(elementType, universe);
elements = new long[(universe.length + 63) >>> 6];
}
void addRange(E from, E to) {
int fromIndex = from.ordinal() >>> 6;
int toIndex = to.ordinal() >>> 6;
if (fromIndex == toIndex) {
elements[fromIndex] = (-1L >>> (from.ordinal() - to.ordinal() - 1))
<< from.ordinal();
} else {
elements[fromIndex] = (-1L << from.ordinal());
for (int i = fromIndex + 1; i < toIndex; i++)
elements[i] = -1;
elements[toIndex] = -1L >>> (63 - to.ordinal());
}
size = to.ordinal() - from.ordinal() + 1;
}
void addAll() {
for (int i = 0; i < elements.length; i++)
elements[i] = -1;
elements[elements.length - 1] >>>= -universe.length;
size = universe.length;
}
void complement() {
for (int i = 0; i < elements.length; i++)
elements[i] = ~elements[i];
elements[elements.length - 1] &= (-1L >>> -universe.length);
size = universe.length - size;
}
/**
* Returns an iterator over the elements contained in this set. The
* iterator traverses the elements in their natural order (which is
* the order in which the enum constants are declared). The returned
* Iterator is a "weakly consistent" iterator that will never throw {@link
* ConcurrentModificationException}.
*
* @return an iterator over the elements contained in this set
*/
public Iterator iterator() {
return new EnumSetIterator<>();
}
private class EnumSetIterator> implements Iterator {
/**
* A bit vector representing the elements in the current "word"
* of the set not yet returned by this iterator.
*/
long unseen;
/**
* The index corresponding to unseen in the elements array.
*/
int unseenIndex = 0;
/**
* The bit representing the last element returned by this iterator
* but not removed, or zero if no such element exists.
*/
long lastReturned = 0;
/**
* The index corresponding to lastReturned in the elements array.
*/
int lastReturnedIndex = 0;
EnumSetIterator() {
unseen = elements[0];
}
@Override
public boolean hasNext() {
while (unseen == 0 && unseenIndex < elements.length - 1)
unseen = elements[++unseenIndex];
return unseen != 0;
}
@Override
@SuppressWarnings("unchecked")
public E next() {
if (!hasNext())
throw new NoSuchElementException();
lastReturned = unseen & -unseen;
lastReturnedIndex = unseenIndex;
unseen -= lastReturned;
return (E) universe[(lastReturnedIndex << 6)
+ Long.numberOfTrailingZeros(lastReturned)];
}
@Override
public void remove() {
if (lastReturned == 0)
throw new IllegalStateException();
final long oldElements = elements[lastReturnedIndex];
elements[lastReturnedIndex] &= ~lastReturned;
if (oldElements != elements[lastReturnedIndex]) {
size--;
}
lastReturned = 0;
}
}
/**
* Returns the number of elements in this set.
*
* @return the number of elements in this set
*/
public int size() {
return size;
}
/**
* Returns true if this set contains no elements.
*
* @return true if this set contains no elements
*/
public boolean isEmpty() {
return size == 0;
}
/**
* Returns true if this set contains the specified element.
*
* @param e element to be checked for containment in this collection
* @return true if this set contains the specified element
*/
public boolean contains(Object e) {
if (e == null)
return false;
Class> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
return false;
int eOrdinal = ((Enum>)e).ordinal();
return (elements[eOrdinal >>> 6] & (1L << eOrdinal)) != 0;
}
// Modification Operations
/**
* Adds the specified element to this set if it is not already present.
*
* @param e element to be added to this set
* @return true if the set changed as a result of the call
*
* @throws NullPointerException if e is null
*/
public boolean add(E e) {
typeCheck(e);
int eOrdinal = e.ordinal();
int eWordNum = eOrdinal >>> 6;
long oldElements = elements[eWordNum];
elements[eWordNum] |= (1L << eOrdinal);
boolean result = (elements[eWordNum] != oldElements);
if (result)
size++;
return result;
}
/**
* Removes the specified element from this set if it is present.
*
* @param e element to be removed from this set, if present
* @return true if the set contained the specified element
*/
public boolean remove(Object e) {
if (e == null)
return false;
Class> eClass = e.getClass();
if (eClass != elementType && eClass.getSuperclass() != elementType)
return false;
int eOrdinal = ((Enum>)e).ordinal();
int eWordNum = eOrdinal >>> 6;
long oldElements = elements[eWordNum];
elements[eWordNum] &= ~(1L << eOrdinal);
boolean result = (elements[eWordNum] != oldElements);
if (result)
size--;
return result;
}
// Bulk Operations
/**
* Returns true if this set contains all of the elements
* in the specified collection.
*
* @param c collection to be checked for containment in this set
* @return true if this set contains all of the elements
* in the specified collection
* @throws NullPointerException if the specified collection is null
*/
public boolean containsAll(Collection> c) {
if (!(c instanceof JumboEnumSet))
return super.containsAll(c);
JumboEnumSet> es = (JumboEnumSet>)c;
if (es.elementType != elementType)
return es.isEmpty();
for (int i = 0; i < elements.length; i++)
if ((es.elements[i] & ~elements[i]) != 0)
return false;
return true;
}
/**
* Adds all of the elements in the specified collection to this set.
*
* @param c collection whose elements are to be added to this set
* @return true if this set changed as a result of the call
* @throws NullPointerException if the specified collection or any of
* its elements are null
*/
public boolean addAll(Collection extends E> c) {
if (!(c instanceof JumboEnumSet))
return super.addAll(c);
JumboEnumSet> es = (JumboEnumSet>)c;
if (es.elementType != elementType) {
if (es.isEmpty())
return false;
else
throw new ClassCastException(
es.elementType + " != " + elementType);
}
for (int i = 0; i < elements.length; i++)
elements[i] |= es.elements[i];
return recalculateSize();
}
/**
* Removes from this set all of its elements that are contained in
* the specified collection.
*
* @param c elements to be removed from this set
* @return true if this set changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
public boolean removeAll(Collection> c) {
if (!(c instanceof JumboEnumSet))
return super.removeAll(c);
JumboEnumSet> es = (JumboEnumSet>)c;
if (es.elementType != elementType)
return false;
for (int i = 0; i < elements.length; i++)
elements[i] &= ~es.elements[i];
return recalculateSize();
}
/**
* Retains only the elements in this set that are contained in the
* specified collection.
*
* @param c elements to be retained in this set
* @return true if this set changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
public boolean retainAll(Collection> c) {
if (!(c instanceof JumboEnumSet))
return super.retainAll(c);
JumboEnumSet> es = (JumboEnumSet>)c;
if (es.elementType != elementType) {
boolean changed = (size != 0);
clear();
return changed;
}
for (int i = 0; i < elements.length; i++)
elements[i] &= es.elements[i];
return recalculateSize();
}
/**
* Removes all of the elements from this set.
*/
public void clear() {
Arrays.fill(elements, 0);
size = 0;
}
/**
* Compares the specified object with this set for equality. Returns
* true if the given object is also a set, the two sets have
* the same size, and every member of the given set is contained in
* this set.
*
* @param o object to be compared for equality with this set
* @return true if the specified object is equal to this set
*/
public boolean equals(Object o) {
if (!(o instanceof JumboEnumSet))
return super.equals(o);
JumboEnumSet> es = (JumboEnumSet>)o;
if (es.elementType != elementType)
return size == 0 && es.size == 0;
return Arrays.equals(es.elements, elements);
}
/**
* Recalculates the size of the set. Returns true if it's changed.
*/
private boolean recalculateSize() {
int oldSize = size;
size = 0;
for (long elt : elements)
size += Long.bitCount(elt);
return size != oldSize;
}
public EnumSet clone() {
JumboEnumSet result = (JumboEnumSet) super.clone();
result.elements = result.elements.clone();
return result;
}
}
public class EnumMap, V> extends AbstractMap
implements java.io.Serializable, Cloneable
{
/**
* The Class object for the enum type of all the keys of this map.
*
* @serial
*/
private final Class keyType;
/**
* All of the values comprising K. (Cached for performance.)
*/
private transient K[] keyUniverse;
/**
* Array representation of this map. The ith element is the value
* to which universe[i] is currently mapped, or null if it isn't
* mapped to anything, or NULL if it's mapped to null.
*/
private transient Object[] vals; //值为i对应着vals[i]的值
/**
* The number of mappings in this map.
*/
private transient int size = 0;
/**
* Distinguished non-null value for representing null values.
*/
private static final Object NULL = new Object() {
public int hashCode() {
return 0;
}
public String toString() {
return "java.util.EnumMap.NULL";
}
};
private Object maskNull(Object value) {
return (value == null ? NULL : value);
}
@SuppressWarnings("unchecked")
private V unmaskNull(Object value) {
return (V)(value == NULL ? null : value);
}
private static final Enum>[] ZERO_LENGTH_ENUM_ARRAY = new Enum>[0];
/**
* Creates an empty enum map with the specified key type.
*
* @param keyType the class object of the key type for this enum map
* @throws NullPointerException if keyType is null
*/
public EnumMap(Class keyType) {
this.keyType = keyType;
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
}
/**
* Creates an enum map with the same key type as the specified enum
* map, initially containing the same mappings (if any).
*
* @param m the enum map from which to initialize this enum map
* @throws NullPointerException if m is null
*/
public EnumMap(EnumMap m) {
keyType = m.keyType;
keyUniverse = m.keyUniverse;
vals = m.vals.clone();
size = m.size;
}
/**
* Creates an enum map initialized from the specified map. If the
* specified map is an EnumMap instance, this constructor behaves
* identically to {@link #EnumMap(EnumMap)}. Otherwise, the specified map
* must contain at least one mapping (in order to determine the new
* enum map's key type).
*
* @param m the map from which to initialize this enum map
* @throws IllegalArgumentException if m is not an
* EnumMap instance and contains no mappings
* @throws NullPointerException if m is null
*/
public EnumMap(Map m) {
if (m instanceof EnumMap) {
EnumMap em = (EnumMap) m;
keyType = em.keyType;
keyUniverse = em.keyUniverse;
vals = em.vals.clone();
size = em.size;
} else {
if (m.isEmpty())
throw new IllegalArgumentException("Specified map is empty");
keyType = m.keySet().iterator().next().getDeclaringClass();
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
putAll(m);
}
}
// Query Operations
/**
* Returns the number of key-value mappings in this map.
*
* @return the number of key-value mappings in this map
*/
public int size() {
return size;
}
/**
* Returns true if this map maps one or more keys to the
* specified value.
*
* @param value the value whose presence in this map is to be tested
* @return true if this map maps one or more keys to this value
*/
public boolean containsValue(Object value) {
value = maskNull(value);
for (Object val : vals)
if (value.equals(val))
return true;
return false;
}
/**
* Returns true if this map contains a mapping for the specified
* key.
*
* @param key the key whose presence in this map is to be tested
* @return true if this map contains a mapping for the specified
* key
*/
public boolean containsKey(Object key) {
return isValidKey(key) && vals[((Enum>)key).ordinal()] != null;
}
private boolean containsMapping(Object key, Object value) {
return isValidKey(key) &&
maskNull(value).equals(vals[((Enum>)key).ordinal()]);
}
/**
* Returns the value to which the specified key is mapped,
* or {@code null} if this map contains no mapping for the key.
*
* More formally, if this map contains a mapping from a key
* {@code k} to a value {@code v} such that {@code (key == k)},
* then this method returns {@code v}; otherwise it returns
* {@code null}. (There can be at most one such mapping.)
*
*
A return value of {@code null} does not necessarily
* indicate that the map contains no mapping for the key; it's also
* possible that the map explicitly maps the key to {@code null}.
* The {@link #containsKey containsKey} operation may be used to
* distinguish these two cases.
*/
public V get(Object key) {
return (isValidKey(key) ?
unmaskNull(vals[((Enum>)key).ordinal()]) : null);
}
// Modification Operations
/**
* Associates the specified value with the specified key in this map.
* If the map previously contained a mapping for this key, the old
* value is replaced.
*
* @param key the key with which the specified value is to be associated
* @param value the value to be associated with the specified key
*
* @return the previous value associated with specified key, or
* null if there was no mapping for key. (A null
* return can also indicate that the map previously associated
* null with the specified key.)
* @throws NullPointerException if the specified key is null
*/
public V put(K key, V value) {
typeCheck(key);
int index = key.ordinal();
Object oldValue = vals[index];
vals[index] = maskNull(value);
if (oldValue == null)
size++;
return unmaskNull(oldValue);
}
/**
* Removes the mapping for this key from this map if present.
*
* @param key the key whose mapping is to be removed from the map
* @return the previous value associated with specified key, or
* null if there was no entry for key. (A null
* return can also indicate that the map previously associated
* null with the specified key.)
*/
public V remove(Object key) {
if (!isValidKey(key))
return null;
int index = ((Enum>)key).ordinal();
Object oldValue = vals[index];
vals[index] = null;
if (oldValue != null)
size--;
return unmaskNull(oldValue);
}
private boolean removeMapping(Object key, Object value) {
if (!isValidKey(key))
return false;
int index = ((Enum>)key).ordinal();
if (maskNull(value).equals(vals[index])) {
vals[index] = null;
size--;
return true;
}
return false;
}
/**
* Returns true if key is of the proper type to be a key in this
* enum map.
*/
private boolean isValidKey(Object key) {
if (key == null)
return false;
// Cheaper than instanceof Enum followed by getDeclaringClass
Class> keyClass = key.getClass();
return keyClass == keyType || keyClass.getSuperclass() == keyType;
}
// Bulk Operations
/**
* Copies all of the mappings from the specified map to this map.
* These mappings will replace any mappings that this map had for
* any of the keys currently in the specified map.
*
* @param m the mappings to be stored in this map
* @throws NullPointerException the specified map is null, or if
* one or more keys in the specified map are null
*/
public void putAll(Map extends K, ? extends V> m) {
if (m instanceof EnumMap) {
EnumMap, ?> em = (EnumMap, ?>)m;
if (em.keyType != keyType) {
if (em.isEmpty())
return;
throw new ClassCastException(em.keyType + " != " + keyType);
}
for (int i = 0; i < keyUniverse.length; i++) {
Object emValue = em.vals[i];
if (emValue != null) {
if (vals[i] == null)
size++;
vals[i] = emValue;
}
}
} else {
super.putAll(m);
}
}
/**
* Removes all mappings from this map.
*/
public void clear() {
Arrays.fill(vals, null);
size = 0;
}
// Views
/**
* This field is initialized to contain an instance of the entry set
* view the first time this view is requested. The view is stateless,
* so there's no reason to create more than one.
*/
private transient Set> entrySet;
/**
* Returns a {@link Set} view of the keys contained in this map.
* The returned set obeys the general contract outlined in
* {@link Map#keySet()}. The set's iterator will return the keys
* in their natural order (the order in which the enum constants
* are declared).
*
* @return a set view of the keys contained in this enum map
*/
public Set keySet() {
Set ks = keySet;
if (ks != null)
return ks;
else
return keySet = new KeySet();
}
private class KeySet extends AbstractSet {
public Iterator iterator() {
return new KeyIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsKey(o);
}
public boolean remove(Object o) {
int oldSize = size;
EnumMap.this.remove(o);
return size != oldSize;
}
public void clear() {
EnumMap.this.clear();
}
}
/**
* Returns a {@link Collection} view of the values contained in this map.
* The returned collection obeys the general contract outlined in
* {@link Map#values()}. The collection's iterator will return the
* values in the order their corresponding keys appear in map,
* which is their natural order (the order in which the enum constants
* are declared).
*
* @return a collection view of the values contained in this map
*/
public Collection values() {
Collection vs = values;
if (vs != null)
return vs;
else
return values = new Values();
}
private class Values extends AbstractCollection {
public Iterator iterator() {
return new ValueIterator();
}
public int size() {
return size;
}
public boolean contains(Object o) {
return containsValue(o);
}
public boolean remove(Object o) {
o = maskNull(o);
for (int i = 0; i < vals.length; i++) {
if (o.equals(vals[i])) {
vals[i] = null;
size--;
return true;
}
}
return false;
}
public void clear() {
EnumMap.this.clear();
}
}
/**
* Returns a {@link Set} view of the mappings contained in this map.
* The returned set obeys the general contract outlined in
* {@link Map#keySet()}. The set's iterator will return the
* mappings in the order their keys appear in map, which is their
* natural order (the order in which the enum constants are declared).
*
* @return a set view of the mappings contained in this enum map
*/
public Set> entrySet() {
Set> es = entrySet;
if (es != null)
return es;
else
return entrySet = new EntrySet();
}
private class EntrySet extends AbstractSet> {
public Iterator> iterator() {
return new EntryIterator();
}
public boolean contains(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry,?> entry = (Map.Entry,?>)o;
return containsMapping(entry.getKey(), entry.getValue());
}
public boolean remove(Object o) {
if (!(o instanceof Map.Entry))
return false;
Map.Entry,?> entry = (Map.Entry,?>)o;
return removeMapping(entry.getKey(), entry.getValue());
}
public int size() {
return size;
}
public void clear() {
EnumMap.this.clear();
}
public Object[] toArray() {
return fillEntryArray(new Object[size]);
}
@SuppressWarnings("unchecked")
public T[] toArray(T[] a) {
int size = size();
if (a.length < size)
a = (T[])java.lang.reflect.Array
.newInstance(a.getClass().getComponentType(), size);
if (a.length > size)
a[size] = null;
return (T[]) fillEntryArray(a);
}
private Object[] fillEntryArray(Object[] a) {
int j = 0;
for (int i = 0; i < vals.length; i++)
if (vals[i] != null)
a[j++] = new AbstractMap.SimpleEntry<>(
keyUniverse[i], unmaskNull(vals[i]));
return a;
}
}
private abstract class EnumMapIterator implements Iterator {
// Lower bound on index of next element to return
int index = 0;
// Index of last returned element, or -1 if none
int lastReturnedIndex = -1;
public boolean hasNext() {
while (index < vals.length && vals[index] == null)
index++;
return index != vals.length;
}
public void remove() {
checkLastReturnedIndex();
if (vals[lastReturnedIndex] != null) {
vals[lastReturnedIndex] = null;
size--;
}
lastReturnedIndex = -1;
}
private void checkLastReturnedIndex() {
if (lastReturnedIndex < 0)
throw new IllegalStateException();
}
}
private class KeyIterator extends EnumMapIterator {
public K next() {
if (!hasNext())
throw new NoSuchElementException();
lastReturnedIndex = index++;
return keyUniverse[lastReturnedIndex];
}
}
private class ValueIterator extends EnumMapIterator {
public V next() {
if (!hasNext())
throw new NoSuchElementException();
lastReturnedIndex = index++;
return unmaskNull(vals[lastReturnedIndex]);
}
}
private class EntryIterator extends EnumMapIterator> {
private Entry lastReturnedEntry;
public Map.Entry next() {
if (!hasNext())
throw new NoSuchElementException();
lastReturnedEntry = new Entry(index++);
return lastReturnedEntry;
}
public void remove() {
lastReturnedIndex =
((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
super.remove();
lastReturnedEntry.index = lastReturnedIndex;
lastReturnedEntry = null;
}
private class Entry implements Map.Entry {
private int index;
private Entry(int index) {
this.index = index;
}
public K getKey() {
checkIndexForEntryUse();
return keyUniverse[index];
}
public V getValue() {
checkIndexForEntryUse();
return unmaskNull(vals[index]);
}
public V setValue(V value) {
checkIndexForEntryUse();
V oldValue = unmaskNull(vals[index]);
vals[index] = maskNull(value);
return oldValue;
}
public boolean equals(Object o) {
if (index < 0)
return o == this;
if (!(o instanceof Map.Entry))
return false;
Map.Entry,?> e = (Map.Entry,?>)o;
V ourValue = unmaskNull(vals[index]);
Object hisValue = e.getValue();
return (e.getKey() == keyUniverse[index] &&
(ourValue == hisValue ||
(ourValue != null && ourValue.equals(hisValue))));
}
public int hashCode() {
if (index < 0)
return super.hashCode();
return entryHashCode(index);
}
public String toString() {
if (index < 0)
return super.toString();
return keyUniverse[index] + "="
+ unmaskNull(vals[index]);
}
private void checkIndexForEntryUse() {
if (index < 0)
throw new IllegalStateException("Entry was removed");
}
}
}
// Comparison and hashing
/**
* Compares the specified object with this map for equality. Returns
* true if the given object is also a map and the two maps
* represent the same mappings, as specified in the {@link
* Map#equals(Object)} contract.
*
* @param o the object to be compared for equality with this map
* @return true if the specified object is equal to this map
*/
public boolean equals(Object o) {
if (this == o)
return true;
if (o instanceof EnumMap)
return equals((EnumMap,?>)o);
if (!(o instanceof Map))
return false;
Map,?> m = (Map,?>)o;
if (size != m.size())
return false;
for (int i = 0; i < keyUniverse.length; i++) {
if (null != vals[i]) {
K key = keyUniverse[i];
V value = unmaskNull(vals[i]);
if (null == value) {
if (!((null == m.get(key)) && m.containsKey(key)))
return false;
} else {
if (!value.equals(m.get(key)))
return false;
}
}
}
return true;
}
private boolean equals(EnumMap,?> em) {
if (em.keyType != keyType)
return size == 0 && em.size == 0;
// Key types match, compare each value
for (int i = 0; i < keyUniverse.length; i++) {
Object ourValue = vals[i];
Object hisValue = em.vals[i];
if (hisValue != ourValue &&
(hisValue == null || !hisValue.equals(ourValue)))
return false;
}
return true;
}
/**
* Returns the hash code value for this map. The hash code of a map is
* defined to be the sum of the hash codes of each entry in the map.
*/
public int hashCode() {
int h = 0;
for (int i = 0; i < keyUniverse.length; i++) {
if (null != vals[i]) {
h += entryHashCode(i);
}
}
return h;
}
private int entryHashCode(int index) {
return (keyUniverse[index].hashCode() ^ vals[index].hashCode());
}
/**
* Returns a shallow copy of this enum map. (The values themselves
* are not cloned.
*
* @return a shallow copy of this enum map
*/
@SuppressWarnings("unchecked")
public EnumMap clone() {
EnumMap result = null;
try {
result = (EnumMap) super.clone();
} catch(CloneNotSupportedException e) {
throw new AssertionError();
}
result.vals = result.vals.clone();
result.entrySet = null;
return result;
}
/**
* Throws an exception if e is not of the correct type for this enum set.
*/
private void typeCheck(K key) {
Class> keyClass = key.getClass();
if (keyClass != keyType && keyClass.getSuperclass() != keyType)
throw new ClassCastException(keyClass + " != " + keyType);
}
/**
* Returns all of the values comprising K.
* The result is uncloned, cached, and shared by all callers.
*/
private static > K[] getKeyUniverse(Class keyType) {
return SharedSecrets.getJavaLangAccess()
.getEnumConstantsShared(keyType);
}
private static final long serialVersionUID = 458661240069192865L;
/**
* Save the state of the EnumMap instance to a stream (i.e.,
* serialize it).
*
* @serialData The size of the enum map (the number of key-value
* mappings) is emitted (int), followed by the key (Object)
* and value (Object) for each key-value mapping represented
* by the enum map.
*/
private void writeObject(java.io.ObjectOutputStream s)
throws java.io.IOException
{
// Write out the key type and any hidden stuff
s.defaultWriteObject();
// Write out size (number of Mappings)
s.writeInt(size);
// Write out keys and values (alternating)
int entriesToBeWritten = size;
for (int i = 0; entriesToBeWritten > 0; i++) {
if (null != vals[i]) {
s.writeObject(keyUniverse[i]);
s.writeObject(unmaskNull(vals[i]));
entriesToBeWritten--;
}
}
}
/**
* Reconstitute the EnumMap instance from a stream (i.e.,
* deserialize it).
*/
@SuppressWarnings("unchecked")
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException
{
// Read in the key type and any hidden stuff
s.defaultReadObject();
keyUniverse = getKeyUniverse(keyType);
vals = new Object[keyUniverse.length];
// Read in size (number of Mappings)
int size = s.readInt();
// Read the keys and values, and put the mappings in the HashMap
for (int i = 0; i < size; i++) {
K key = (K) s.readObject();
V value = (V) s.readObject();
put(key, value);
}
}
}
因为枚举类型是final修饰的类,所有后代不能覆写他的方法,但如下面所示的代码可以覆写枚举类的方法。其实是通过匿名内部类来实现的。
public enum OverrideConstantSpecific {
NUT, BOLT,
WASHER {
void f() { print("Overridden method"); }
};
void f() { print("default behavior"); }
public static void main(String[] args) {
for(OverrideConstantSpecific ocs : values()) {
printnb(ocs + ": ");
ocs.f();
}
}
} /* Output:
NUT: default behavior
BOLT: default behavior
WASHER: Overridden method
*///:~