简单看看java之枚举

2019-08-09 00:00:00 java 简单 枚举

  枚举类这个类用的比较少,对这个不怎么熟悉,最近看源码刚好可以好好了解一下,那么,枚举Enum是什么呢?在jdk中,Enum是一个抽象类下图所示,这就说明这个类是不能进行实例化的,那么我们应该怎么使用呢?

《简单看看java之枚举》

 

1.枚举类的基本使用

  简单的使用一下(随便借用的一个栗子),我们可以直接把枚举类当作一个常量一样来使用这个类,那么问题来了,下面的这个枚举类和上面说的那么Enum抽象类是什么关系呢?

  肯定是继承啊,这里很像Cglib动态代理,但肯定不是代理。。。反正下面这个类经过编译,就会编译出两个字节码文件,一个是TestEnum类。另外一个就是Week类(这个类自动继承Enum抽象类);

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类中到底是些什么东西;

// 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来声明的,但是实际上就是一个类,是为了让我们用起来方便简洁,才这样设计的(虽然我还是觉得枚举很怪。。。);

 

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");
    }
}

 

   这个抽象类方法也不是很多,很容易,现在再来看看枚举类应该就很容易了;

   我们理一下思路:当我们在一个平常的类中使用了枚举类的话,而且这个枚举类中定义了很多个实例,那么在使用的时候就会将枚举类拿出来和类分开编译,这个枚举类中的多个实例(这里每个实例都有自己的数组下标)都给实例化出来,并且放到一个实例数组中;其中每个枚举类都会自动继承Enum这个抽象类,我们可以根据对应的枚举类来获取每个实例的对象,当然枚举类可能也有多个,那么也可以根据Enum这个抽象类来获取对应枚举类中的实例,并转化为该枚举类的类型返回。。。

  原理就这么多吧!下面来看看枚举类的一些其他用法;

 

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类了),可以有自己的属性,方法,也可以覆盖父类的方法(可以自己试试),就跟平常类一样的使用!就是写法略怪,习惯就好!!!

  话说昨天下午弄了好久,终于被我找到在博客园配置出了血小板看板娘了,哈哈哈,我现在声明一句:血小板就是我老婆,不接受反驳!嘿嘿嘿@_@

相关文章