天天看点

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

一:枚举类

枚举是JDK1.5添加的,在枚举类型出来之前,我们都是以定义常量来代替,比如:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

这种定义常量的方式也是有一些不足的,如int值相同的情况下,编译期并不会提示我们的,所以很容易造成混淆。

定义枚举类的一般语法:任意两个枚举成员不能具有相同的名称,多个枚举成员之间使用逗号分隔,枚举表示的类型其取值是必须有限的

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

二:枚举类原理

把刚才定义的Date枚举类编译后再反编译class文件来看一下:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

可以看到,使用关键字enum定义的枚举类型,在编译期后,也将转换成为一个实实在在的类,而在该类中,会存在每个在枚举类型中定义好变量的对应实例对象,如上述的ONE枚举类型对应public static final Date ONE;,同时编译器会为该类创建两个方法,分别是values()和valueOf()。

  • 枚举类实际上也是一个类,默认继承于java.lang.Enum类,并且此类是final的,不可被继承,又由于java是单继承已经默认继承Enum所以我们定义的Date枚举类是不允许继承其他类的。
  • 默认生成私有构造函数,只能由虚拟机去创建,不允许外部直接创建枚举类对象的。
  • 定义的枚举实际上是枚举类型的常量。

java.lang.Enum源码

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用
java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

下面例子测试其方法:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

运行输出:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

Values()方法与ValueOf()方法

values()方法和valueOf(String name)方法是编译器生成的static方法,在Enum类中并没出现values()方法,但valueOf()方法还是有出现的,只不过编译器生成的valueOf()方法需传递一个name参数,而Enum自带的静态方法valueOf()则需要传递两个方法,其实,编译器生成的valueOf方法最终还是调用了Enum类的valueOf方法:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

运行输出:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

values()方法的作用就是获取枚举类中的所有变量,并作为数组返回。

valueOf(String name)方法与Enum类中的valueOf方法的作用类似根据名称获取枚举变量。

三:枚举类使用

  • enum 与 class、interface 具有相同地位,但是不能继承与被继承,也不能创建实例,只能由JVM去创建。
  • 可以实现多个接口,也可以拥有构造器、成员方法、成员变量。

实现接口

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

定义构造函数

注意:只能是私有的构造函数或默认

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

定义成员方法和成员变量

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

EnumMap

java.util.EnumSet和java.util.EnumMap是两个枚举集合。EnumMap继承了AbstractMap类,因此EnumMap具备一般map的使用方法,主要通过一个保存key的数组K[] keyUniverse和一个保存value的数组Object[] vals来操作。

源码:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用
java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用
java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用
java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

下面例子测试其方法:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

运行输出:

{ONE=1, THREE=3}
           

EnumSet

EnumSet是与枚举类型一起使用的专用 Set 集合,EnumSet 中所有元素都必须是枚举类型。注意EnumSet不允许使用 null 元素。试图插入 null 元素将抛出 NullPointerException,但试图测试判断是否存在null 元素或移除 null 元素则不会抛出异常,与大多数collection 实现一样,EnumSet不是线程安全的,因此在多线程环境下应该注意数据同步问题。

public abstract class EnumSet> extends AbstractSet
           
implements Cloneable, java.io.Serializable
           
//元素的class
           
final Class elementType;
           
final Enum>[] universe;
           
private static Enum>[] ZERO_LENGTH_ENUM_ARRAY = new Enum>[0];
           
this.elementType = elementType;
           
this.universe = universe;
           
}
           
//创建一个具有指定元素类型的空EnumSet。
           
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);
           
}
           
//创建一个指定元素类型并包含所有枚举值的EnumSet
           
EnumSet result = noneOf(elementType);
           
result.addAll();
           
return result;
           
}
           
abstract void addAll();
           
创建一个包含参数容器中的所有元素的EnumSet
           
return s.clone();
           
}
           
return ((EnumSet)c).clone();
           
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;
           
}
           
}
           
// 初始集合包括指定集合的补集
           
EnumSet result = copyOf(s);
           
result.complement();
           
return result;
           
}
           
// 创建一个包括参数中所有元素的EnumSet
           
EnumSet result = noneOf(e.getDeclaringClass());
           
result.add(e);
           
return result;
           
}
           
EnumSet result = noneOf(e1.getDeclaringClass());
           
result.add(e1);
           
result.add(e2);
           
return result;
           
}
           
EnumSet result = noneOf(e1.getDeclaringClass());
           
result.add(e1);
           
result.add(e2);
           
result.add(e3);
           
return result;
           
}
           
EnumSet result = noneOf(e1.getDeclaringClass());
           
result.add(e1);
           
result.add(e2);
           
result.add(e3);
           
result.add(e4);
           
return result;
           
}
           
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;
           
}
           
@SafeVarargs
           
EnumSet result = noneOf(first.getDeclaringClass());
           
result.add(first);
           
for (E e : rest)
           
result.add(e);
           
return result;
           
}
           
// 创建一个包括枚举值中指定范围元素的EnumSet
           
if (from.compareTo(to) > 0)
           
throw new IllegalArgumentException(from + " > " + to);
           
EnumSet result = noneOf(from.getDeclaringClass());
           
result.addRange(from, to);
           
return result;
           
}
           
abstract void addRange(E from, E to);
           
@SuppressWarnings("unchecked")
           
return (EnumSet) super.clone();
           
throw new AssertionError(e);
           
}
           
}
           
abstract void complement();
           
Class> eClass = e.getClass();
           
if (eClass != elementType && eClass.getSuperclass() != elementType)
           
throw new ClassCastException(eClass + " != " + elementType);
           
}
           
return SharedSecrets.getJavaLangAccess()
           
.getEnumConstantsShared(elementType);
           
}
           
}
           

下面例子测试其方法:

创建EnumSet并不能使用new关键字,因为它是个抽象类,而应该使用其提供的静态工厂方法,EnumSet的静态工厂方法比较多,如下:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用
java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

运行输出:

java 枚举_吃透Java基础十一:枚举一:枚举类二:枚举类原理三:枚举类使用

继续阅读