枚举类基本使用

Java 利用枚举实现单例模式
Java枚举类,你真的了解吗
Java枚举类

1. 基本用法

枚举类也是类,里面有两个系统自带的属性nameordinal(这一点下面再说),一个枚举可以拥有成员变量,成员方法,构造方法。先来看枚举最基本的用法:

enum Type{
    A,B,C,D;
}

创建enum时,编译器会自动为我们生成一个继承自java.lang.Enum的类,我们上面的enum可以简单看作

class Type extends Enum{
    public static final Type A;
    public static final Type B;
    ...
}

对于上面的例子,我们可以把Type看作一个类,而把A,B,C,D看作类的Type的实例,枚举类的实例和一般实例的创建不同,他只能使用上面的方式进行创建,一个enum的构造方法限制是private的,也就是不允许我们调用

2. 关于java.lang.Enum

上面说到创建enum时,编译器会自动为我们生成一个继承自java.lang.Enum的类,那这个java.lang.Enum包括什么?
在这里插入图片描述
可以看到它有两个成员变量,nameordinal
其实name就是我们创建的实例的名字,而ordinal是定义的次序(A,B,C,D)

几个方法

  • valueOf()
    返回当前枚举类的name属性,如果没有,则throw new java.lang.IllegalArgumentException()。具体可以查看java.lang.Enum源码

  • values()
    是编译器自动生成的方法,Enum中并没有该方法,返回包括所有枚举变量的数组

-toString(),name()
很简单,两个方法一样,返回当前枚举类变量的name属性。
如果默认的toString()不能满足需求,我们可以结合switch来灵活的实现toString()方法

  • ordinal()
    枚举类会给所有的枚举变量一个默认的次序,该次序从0开始,是根据我们定义的次序来排序的。而ordinal()方法就是获取这个次序(或者说下标)

  • compareTo()
    比较的是两个枚举变量的次序,返回两个次序相减后的结果,具体可以扒源码

2. 类方法和实例方法

我们可以把Type看作一个类,而把A,B,C,D看作Type的一个实例,同样,在enum中,我们可以定义类和实例的变量以及方法
① 如果打算自定义自己的方法,那么必须在enum实例序列的最后添加一个分号
Java 要求必须先定义 enum 实例

看下面的代码:

enum Type{
    A("a"),
    B("b"),
    C("c"),
    D("d");
	//在原有的基础上,添加了类方法和实例方法。
	//我们把Type看做一个类,那么enum中静态的域和方法,都可以视作类方法。
	//和我们调用普通的静态方法一样,这里调用类方法也是通过  Type.getValue()即可调用,访问类属性也是通过Type.value即可访问。
    static int value;
    public static int getValue() {
        return value;
    }
	//下面的是实例方法,也就是每个实例才能调用的方法
	//那么实例是什么呢?没错,就是A,B,C,D。所以我们调用实例方法,也就通过 Type.A.getType()来调用就可以了。
    String type;
    /**
    * 构造方法必然是private修饰的
    * 就算不写,也是默认的
    */
	private Type(String type){
		this.type = type;
	}
	
    public String getType() {
        return type;
    }
}

最后,对于某个实例而言,还可以实现自己的实例方法。再看下下面的代码:

enum Type{
A{
    public String getType() {
        return "I will not tell you";
    }
},B,C,D;
static int value;

public static int getValue() {
    return value;
}

String type;
public String getType() {
    return type;
 }
}

这里,A实例后面的{…}就是属于A的实例方法,可以通过覆盖原本的方法,实现属于自己的定制。
除此之外,我们还可以添加抽象方法在enum中,强制ABCD都实现各自的处理逻辑:

enum Type{
    A{
        public String getType() {
            return "A";
        }
    },B {
        @Override
        public String getType() {
            return "B";
        }
    },C {
        @Override
        public String getType() {
            return "C";
        }
    },D {
        @Override
        public String getType() {
            return "D";
        }
    };

    public abstract String getType();
}

3. 枚举与反射

可以通过反射获取枚举对象

import java.lang.reflect.Constructor;

public enum Week {
    //本文的枚举类变量,枚举类实例,name属性指的就是MONDAY
    //这类的变量
    MONDAY(0, "星期一"),
    TUESDAY(1, "星期二"),
    WEDNESDAY(2, "星期三"),
    THURSDAY(3, "星期四"),
    FRIDAY(4, "星期五"),
    SATURDAY(5, "星期六"),
    //最后一个类型必须要用分号结束
    SUNDAY(6, "星期日");

    private int num;
    private String desc;

    /**
     * 构造方法必然是private修饰的
     * 就算不写,也是默认的
     *
     * @param num
     * @param desc
     */
    private Week(int num, String desc) {
        this.num = num;
        this.desc = desc;
    }

    private Week(){
        
    }

    public String getDesc() {
        return desc;
    }

    public int getNum() {
        return num;
    }
}

可以通过反射获取枚举对象

// 1.得到枚举类对象
 Class<?> clazz = Week.class;
 // 2.得到枚举类中的所有实例
 Object[] enumInstances = clazz.getEnumConstants();
 Method getDesc= clazz.getMethod("getDesc");
 Method getNextDay= clazz.getMethod("getNextDay");
 for (Object instance : enumInstances){
     // 3.调用对应方法,得到枚举类中实例的值与实现的抽象方法
     System.out.println("desc=" + getDesc.invoke(obj) + "; nextDay=" + getNextDay.invoke(obj));
 }

但是不能通过反射调用其构造方法

public static void main(String[] args) throws Exception {
    Class clazz = Week.class;
    Constructor constructor = clazz.getDeclaredConstructor(String.class, int.class);
    constructor.setAccessible(true);
    Object instance = constructor.newInstance();
}

在这里插入图片描述
这是因为jdk底层就为我们对反射进行处理了

if ((clazz.getModifiers() & Modifier.ENUM) != 0)
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; 

正因为如此 我们可以使用枚举实现更为安全的单例模式

4. 策略枚举

如果多个(但非所有)枚举常量同时共享相同的行为,则要考虑策略枚举(effective java p129)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值