枚举 - 枚举基础

在学习枚举和注解章节之前,我们先来看一下枚举和注解的基础知识。

1.枚举类的方法。

2.枚举的简单使用。


1.枚举类的方法。

我们所有的枚举实际上是继承一个枚举类(java.lang.Enum),这个类本身提供了很多方法供继承他的枚举使用,我们来看一下这些方法的作用。

a. 我们先看下面代码,首先我们可以知道枚举类本身是一个抽象的类,他无法直接创建对象,所有枚举必须继承这个抽象类。他还实现了Comparable和序列化的接口,是支持比较和序列化的。

public abstract class Enum<E extends Enum<E>>
        implements Comparable<E>, Serializable

b.ordinal()

定义了枚举后会有一定的顺序,这个方法返回的是实例在声明时的次序。


c.valueOf()

看下面源码,他是一个静态的方法,通过它可以通过传入枚举的name得到枚举对象。

    public static <T extends Enum<T>> T valueOf(Class<T> 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);
    }


d. readObject()

看下面源码,枚举为了保证枚举的唯一性,重写了readObject,阻止枚举实例在序列化的时候生成另外的对象。枚举的序列化和反序列化是直接通过name来进行的。序列化时通过传入name和反序列化是把name传入到valueOf()方法中来得到实例对象。

    /**
     * prevent default deserialization
     */
    private void readObject(ObjectInputStream in) throws IOException,
        ClassNotFoundException {
        throw new InvalidObjectException("can't deserialize enum");
    }


e. values()

这个方法可以得到所有的枚举实例,但是我在枚举的抽象类中没有发现这个方法。是编译器在编译枚举类的时候添加上去的。


2.枚举的简单使用。

a. 看下面代码,定义了一个颜色的枚举。首先Color是继承上面的抽象枚举类,他自己加了两个成员变量。四个颜色对象分别调用自定义的构造方法生成四个枚举对象。

public enum Color {
     
     RED("红色", 1), GREEN("绿色", 2), BLANK("白色", 3), YELLO("黄色", 4);
     
     
    private String name ;
    private int index ;
     
    private Color( String name , int index ){
        this.name = name ;
        this.index = index ;
    }
     
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getIndex() {
        return index;
    }
    public void setIndex(int index) {
        this.index = index;
    }
     
 
}

b. switch语句中可以使用枚举,例子就不写了,能使用的原因是switch只能使用整数值,枚举本身可以通过ordinal来得到整数次序。


c. EnumMap和EnumSet

我们先看一下EnumMap的用法,看下面代码,Size枚举类型,EnumMap的key是枚举类型,初始化的时候需要传递类型信息,如下面例子,传递Size.class。

Map<Size, Integer> map = new EnumMap<>(Size.class);

为什么我们不直接使用HashMap了,枚举完全可以作为HashMap的Key。EnumMap是专门为枚举为Key的Map专门设计的,他有两个优点,一个是内部按顺序保存,输出的时候同样有顺序,另一个是比HashMap更加高效。高效的原因是EnumMap用两个数组来保存,一个保存枚举Key,另一个保存value,根据枚举很容易得到序列(枚举是有序列的),再根据序列很快可以找到Value。

总的来说,EnumMap根据枚举的特性来实现的,他可以高效的存取,如果你需要用到Map,枚举是Key,这个时候你需要考虑EnumMap。


我们再来看一下EnumSet的用法,看下面代码,EnumSet是一个抽象的类不能直接创建,只能利用工厂方法它提供的工厂方法来创建。

EnumSet<Size> set = new EnumSet<Size>(); 错误的

Set<Day> weekend = EnumSet.noneOf(Day.class); 正确的,创建一个空的Day类型的枚举集合

看一下noneOf的源码,RegularEnumSet和JumboEnumSet实现了EnumSet这个抽象类。枚举数量大于64用JumboEnumSet。这是内部自动控制的。

public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> 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);
    }

我们简单说一下EnumSet的实现原理,有兴趣的可以自己看下源码。EnumSet和HashSet不一样,HashSet是基于HashMap来实现的。EnumSet对于EnumMap完全是另一种实现。它采用的是位向量实现的。位向量定义:一个位表示一个元素的状态,一组位表示一个集合的状态,每个位对应一个元素,而状态只可能有两种。我们简单的看一例子,比如我们有一个星期的集合,集合中包括周一到周日,下面一组位向量就可以表示一个星期集合的状态,这个集合包含哪些周一,周三,周五,周日。并且EnumSet的所有的计算都是通过位向量的计算来完成的,非常的高效。

1010101

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值