写点什么

枚举

用户头像
小王同学
关注
发布于: 2020 年 06 月 09 日

1.定义一个枚举

public enum TestEnum
A,B,C //枚举常量值
}



javap TestEunm 反编译class文件

public final class com.mj.TestEnum extends java.lang.Enum<com.mj.TestEnum> {
public static final com.mj.TestEnum A;
public static final com.mj.TestEnum B;
public static final com.mj.TestEnum C;
public static final com.mj.TestEnum D;
public static com.mj.TestEnum[] values();
public static com.mj.TestEnum valueOf(java.lang.String);
static {};
}



*枚举类继承了java.lang.Enum,由于java不支持多继承,所以Enum不能继承其他类,可以实现多个接 口, enum是final的。

*每个枚举常量其实就是自定义的类的类型。

*values()和valueOf并不在java.lang.Enum,编译器为其增加了静态的valuse()和valueOf()方法。

values(); 返回enum实例的数组

valueOf(java.lang.String); 获取指定的枚举常量

*class中有一个getEnumContants()方法,可以对不是枚举的类调用此方法从而获取类中的枚举常量数组。



Enum部分类方法说明:

ordinal() 返回枚举常量定义的顺序序号

name() 返回枚举常量名称

2.在枚举中定义属性和方法

public enum TestEnum1 {
A("ABC", 123),
B("CDE", 456);
String str;
Integer i;
@Override
public String toString() {
return str + "-" + i;
}
TestEnum1(String str, int i) {
this.str = str;
this.i = i;
}
}
class Test1 {
public static void main(String[] args) {
for (TestEnum1 enum1 : TestEnum1.values()) {
System.out.println(enum1.name() + ":" + enum1.toString());
}
}
}
//输出:
//A:ABC-123
//B:CDE-456



1、每个枚举值相当于一个实例,我们每声明一个枚举值就相当于创建了一个class的实例,我们在枚举类中定义的方法、属性信息在每个枚举值的实例中都存在,需要在枚举类中定义相应的构造函数,否则会产生编译器错误(缺少构造函数)。

3.枚举的枚举

1.在最外层的枚举中,定义了若干个枚举常量,在构造函数中说明该枚举只能接收 Food以及Food的子类型的类类型作为参数,Food是一个接口,其中定义了若干个枚举类,表示这些枚举类都是Food的子类型,其语意为Meal中包含了一些枚举常量,而这些枚举常量的构造器参数传的是一个枚举类型。



2.接口中也可以约定枚举方法。



3.Enums的random()方法限定了返回值的上限是Eunm类型,可以理解为所有的枚举类型都被向上转型为Enum类型,而Enum并不具备values()方法,所以我们只能使用 Class的getEnumContants()方法来达到与values()相同的效果。

public enum Meal2 {
APPETIZER(Food.Appetizer.class),
MAINCOURSE(Food.MainCourse.class),
DESSERT(Food.Dessert.class),
COFFEE(Food.Coffee.class);
private Food[] values;
private Meal2(Class<? extends Food> kind) {
values = kind.getEnumConstants();
}
public interface Food {
void eat();
enum Appetizer implements Food {
SALAD, SOUP, SPRING_ROLLS;
@Override
public void eat() {
System.out.println("Appetizer");
}
}
enum MainCourse implements Food {
LASAGNE, BURRITO, PAD_THAI,
LENTILS, HUMMOUS, VINDALOO;
@Override
public void eat() {
System.out.println("MainCourse");
}
}
enum Dessert implements Food {
TIRAMISU, GELATO, BLACK_FOREST_CAKE,
FRUIT, CREME_CARAMEL;
@Override
public void eat() {
System.out.println("Dessert");
}
}
enum Coffee implements Food {
BLACK_COFFEE, DECAF_COFFEE, ESPRESSO,
LATTE, CAPPUCCINO, TEA, HERB_TEA;
@Override
public void eat() {
System.out.println("Coffee");
}
}
}
public Food randomSelection() {
return Enums.random(values);
}
public static void main(String[] args) {
for (int i = 0; i < 5; i++) {
for (Meal2 meal : Meal2.values()) {
Food food = meal.randomSelection();
System.out.println(food);
}
}
}
}
public class Enums {
private static Random rand = new Random(47);
public static <T extends Enum<T>> T random(Class<T> ec) {
return random(ec.getEnumConstants());
}
public static <T> T random(T[] values) {
return values[rand.nextInt(values.length)];
}
}



4.常量相关方法

enum允许程序员为enum实例编写方法,从而为每个eunm实例赋予各自不同行为,你需要在enu中定义一个或多个abstract方法。

public enum ConstantSpecificMethod {
DATE_TIME {
String getInfo() {
return DateFormat.getDateInstance().format(new Date());
}
},
CLASSPATH {
String getInfo() {
return System.getenv("CLASSPATH");
}
},
VERSION {
String getInfo() {
return System.getProperty("java.version");
}
};
abstract String getInfo();
public static void main(String[] args) {
for (ConstantSpecificMethod csm : values()) {
System.out.println(csm.getInfo());
}
}
}



面向对象程序设计中不同的行为与不同的类关联,而通过枚举常量的相关方法,每个enum常量都具备了自己独特的行为,这似乎每个枚举常量都是一个独特的类,而这些类似乎有继承了ConstantSpecificMethod类。然而这只是他们的相似之处,我们不能真的将enum当做一个类型来使用。



public enum LikeClasses {
WINKEN {
void behavior() {
System.out.println("behavior1");
}
},
BLINKEN {
void behavior() {
System.out.println("behavior2");
}
},
NOD {
void behavior() {
System.out.println("behavior3");
}
};
abstract void behavior();
}
public class NotClasses {
//编译报错 Unknown class: 'LikeClasses.WINKEN'
void f1(LikeClasses.WINKEN instance){}
}

原因是由于每个枚举常量都是static final类型的,参考TestEnum反编译结果,由于他们都是static实例,NotClasses无法访问外部类的非static的元素或方法。



我们可以扩展LikeClasses中的枚举常量,使其具备更多的行为,这样做可以使我们的控制逻辑代码与业务逻辑代码分离,也符合软件设计的开闭原则。

public class ConstantSpecificMethodExec {
public void exec(String name) {
ConstantSpecificMethod.valueOf(name).getInfo();
}
}



5.枚举实现单例模式

package com.mj;
public class Singleton {
private Singleton(){
}
enum SingletonEnum {
INSTANCE;
private Singleton singleton;
SingletonEnum() {
singleton = new Singleton();
}
public Singleton getInstance() {
return singleton;
}
}
public static Singleton instance(){
return SingletonEnum.INSTANCE.getInstance();
}
public static void main(String[] args) {
Singleton singleton1 = Singleton.instance();
Singleton singleton2 = Singleton.instance();
System.out.println(singleton1 == singleton2);
}
}
//返回 true



6.枚举实现策略模式

public class Strategy {
enum CRUD {
ADD {
public void exec(){
System.out.println("add");
}
},
QUERY {
public void exec(){
System.out.println("query");
}
},
UPDATE {
public void exec(){
System.out.println("update");
}
},
DEL {
public void exec(){
System.out.println("delete");
}
};
abstract void exec();
}
public static void main(String[] args) {
CRUD.ADD.exec();
CRUD.QUERY.exec();
CRUD.UPDATE.exec();
CRUD.DEL.exec();
}
}
//输出
//add
//query
//update
//delete

7.枚举实现责任链模式

public class ChainResponsibility {
public enum Action {
ACTION1 {
@Override
boolean handle(String message) {
if("QQMgs".equals(message)) {
return true;
}
return false;
}
},
ACTION2 {
@Override
boolean handle(String message) {
if("weChatMsg".equals(message)) {
return true;
}
return false;
}
},
ACTION3 {
@Override
boolean handle(String message) {
if("dingdingMsg".equals(message)) {
return true;
}
return false;
}
};
abstract boolean handle(String message);
}
public static void main(String[] args) {
for(Action action : ChainResponsibility.Action.values()) {
if(action.handle("dingdingMsg")) {
return;
}
}
}
}

8.枚举集合

EnumSet是一个存放枚举类型的set容器,与set类似,出现重复元素存贮时只会保留一个,EnumSet非常快速高效。EnumSet内部由数组实现,添加枚举常量的顺序决定了枚举常量在EnumSet中的顺序。

EnumSet常用方法

noneOf(Class<E> elementType) 生成一个指定枚举类型的空集合

complementOf(EnumSet<E> s) 顾名思义complement是补充的意思,可以创建一个EnumSet的补集

EnumSet是Set接口的一个实现,具备add addAll remveAll 等Set集合的通用方法



EnumMap是一个特殊的Map,它的key必须是一个 Enum常量,EnumMap内部由一个数组实现,所以enum实例定义的顺序决定了它在EnumMap中的顺序,EnumMap也非常的高效。



-------------------------------------------------End------------------------------------------------------

以上内容全部是个人理解,如果错误或不足之处请大家指正,欢迎大家讨论交流。

参考资料

《Java编程思想》

https://mp.weixin.qq.com/s/DgOr7cat8SP0zoY7Ke3toQ

发布于: 2020 年 06 月 09 日阅读数: 72
用户头像

小王同学

关注

还未添加个人签名 2019.03.04 加入

还未添加个人简介

评论

发布
暂无评论
枚举