枚举类这个类用的比较少,对这个不怎么熟悉,最近看源码恰好能够好好了解一下,那么,枚举Enum是什么呢?在jdk中,Enum是一个抽象类下图所示,这就说明这个类是不能进行实例化的,那么咱们应该怎么使用呢?html
1.枚举类的基本使用java
简单的使用一下(随便借用的一个栗子),咱们能够直接把枚举类看成一个常量同样来使用这个类,那么问题来了,下面的这个枚举类和上面说的那么Enum抽象类是什么关系呢?数组
确定是继承啊,这里很像Cglib动态代理,但确定不是代理。。。反正下面这个类通过编译,就会编译出两个字节码文件,一个是TestEnum类。另一个就是Week类(这个类自动继承Enum抽象类);ide
public class TestEnum{ public static void main(String[] args) { System.out.println(Week.MON); } } //这个枚举也能够放在TestEnum里面,充当一个静态内部类 enum Week{ MON,TUE,WED,THU,FRI,SAT,SUN }
咱们能够反编译一下看看Week类中究竟是些什么东西;this
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov. // Jad home page: http://www.kpdus.com/jad.html // Decompiler options: packimports(3) // Source File Name: TestEnum.java //自动的将枚举类Week继承Enum final class Week extends Enum{ public static final Week MON; public static final Week TUE; public static final Week WED; public static final Week THU; public static final Week FRI; public static final Week SAT; public static final Week SUN; private static final Week $VALUES[]; //静态代码块中会实例化七个对象和一个Week数组,用于存放这些实例化对象 static { MON = new Week("MON", 0); TUE = new Week("TUE", 1); WED = new Week("WED", 2); THU = new Week("THU", 3); FRI = new Week("FRI", 4); SAT = new Week("SAT", 5); SUN = new Week("SUN", 6); $VALUES = (new Week[] { MON, TUE, WED, THU, FRI, SAT, SUN }); } //构造器 private Week(String s, int i){ super(s, i); } //生成静态方法values,克隆一份数组,也就是调用这个方法以后就会返回一份包括枚举类中全部实例的数组 public static Week[] values(){ return (Week[])$VALUES.clone(); } //生成静态方法valueOf,经过指定一个枚举类型和实例的名称(字符串),能够转化为一个该枚举类型的对象 public static Week valueOf(String s){ return (Week)Enum.valueOf(Week, s); } }
能够看到Enum虽然咱们用的时候是用Enum来声明的,可是实际上就是一个类,是为了让咱们用起来方便简洁,才这样设计的(虽然我仍是以为枚举很怪。。。);spa
2.看看Enum抽象类设计
咱们发现生成的Week类中构造器会调用父类的构造器,其中i表示每一个实例在数组中的位置,还有values和valueof方法也会调用父类的方法,咱们看看父类全部方法实现,而后再回头看看就清楚了;代理
package java.lang; import java.io.Serializable; import java.io.IOException; import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.ObjectStreamException; //这是一个抽象类,只能被继承 public abstract class Enum<E extends Enum<E>> implements Comparable<E>, Serializable { //枚举类中的实例名称 private final String name; //获取实例名称 public final String name() { return name; } //该实例在实例数组中的位置 private final int ordinal; //获取该实例所在位置 public final int ordinal() { return ordinal; } //此构造器只能由子类本身调用,咱们是不能调用,看到子类Week中的构造器中的super(s, i); protected Enum(String name, int ordinal) { this.name = name; this.ordinal = ordinal; } //输出实例名称 public String toString() { return name; } //重写equal方法和hashcode方法,因为枚举类中都是对象,那么比较的确定就是引用是否是同样了 public final boolean equals(Object other) { return this==other; } public final int hashCode() { return super.hashCode(); } //克隆,这里会直接报错,子类中调用的是Object中的clone方法 protected final Object clone() throws CloneNotSupportedException { throw new CloneNotSupportedException(); } //比较一个枚举类中实例名称的先后顺序 public final int compareTo(E o) { Enum other = (Enum)o; Enum self = this; if (self.getClass() != other.getClass() && self.getDeclaringClass() != other.getDeclaringClass()) throw new ClassCastException(); return self.ordinal - other.ordinal; } //获取枚举实例的Class对象和父类的Class对象,而后判断是否是一个对象,我也不知道干吗用的 public final Class<E> getDeclaringClass() { Class clazz = getClass(); Class zuper = clazz.getSuperclass(); return (zuper == Enum.class) ? clazz : zuper; } //这个方法就是当存在多个枚举类的时候,每一个枚举类都有各自对应的多个实例,这个方法就是将 //根据对应的枚举类的类型,该枚举类中的实例名称,以此来返回该枚举类型的对象 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); } //最没用的方法,Object中也有 protected final void finalize() { } //这两个方法不知道干吗用的。。。都会直接抛异常 private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException { throw new InvalidObjectException("can't deserialize enum"); } private void readObjectNoData() throws ObjectStreamException { throw new InvalidObjectException("can't deserialize enum"); } }
这个抽象类方法也不是不少,很容易,如今再来看看枚举类应该就很容易了;code
咱们理一下思路:当咱们在一个日常的类中使用了枚举类的话,并且这个枚举类中定义了不少个实例,那么在使用的时候就会将枚举类拿出来和类分开编译,这个枚举类中的多个实例(这里每一个实例都有本身的数组下标)都给实例化出来,而且放到一个实例数组中;其中每一个枚举类都会自动继承Enum这个抽象类,咱们能够根据对应的枚举类来获取每一个实例的对象,固然枚举类可能也有多个,那么也能够根据Enum这个抽象类来获取对应枚举类中的实例,并转化为该枚举类的类型返回。。。htm
原理就这么多吧!下面来看看枚举类的一些其余用法;
3.枚举类的简单用法
首先,枚举类能够实现接口:
public interface MyEnum { public void say(); } //实现接口 public enum TestEnum implements MyEnum{ //注意, MON, TUE, WED, THU, FRI, SAT, SUN; @Override public void say() { System.out.println("實現接口--------say"); } public static void main(String[] args) { TestEnum.MON.say(); } }
而后在枚举类中还能有一些属性,以及set/get方法;
package com.wyq.test; public enum TestEnum implements MyEnum{ //注意,这里最后要加分号 MON("mon",12), TUE("tue",12), WED("wed",12), THU("thu",12); private String name; private Integer age; private TestEnum(String name, Integer age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public void say() { System.out.println("实现接口--------say"); } public static void main(String[] args) { System.out.println(TestEnum.MON.getName()+TestEnum.MON.getAge()); } }
4.总结
反正枚举类用的比较少,我就在那个单例模式下用过(天生的单例),至于其余的地方暂时用的比较少,不过当须要用的时候咱们必定要会用啊;
简单的看了看源码以后,其实再回头看看枚举类,其实就跟咱们日常用的类差很少,不能够继承(由于默认已经继承了Enum类了),能够有本身的属性,方法,也能够覆盖父类的方法(能够本身试试),就跟日常类同样的使用!就是写法略怪,习惯就好!!!
话说昨天下午弄了很久,终于被我找到在博客园配置出了血小板看板娘了,哈哈哈,我如今声明一句:血小板就是我老婆,不接受反驳!嘿嘿嘿@_@