原文网址:Java之枚举(enum)--使用/教程/实例_IT利刃出鞘的博客-CSDN博客
简介
说明
本文用示例介绍Java中的枚举(enum)的用法。
使用场景
定义常量、状态机等。
枚举与常量类
常量类
以往设置常量,通常将常量放置在接口中,这样在程序中就可以直接使用了,并且该常量不能被修改,因为在接口中定义的常量时,该常量的修饰符为final与static。如:
public interface IConstants{
public static final int RED = 1;
public static final int BLUE = 2;
public static final int GREEN = 3;
}
枚举与常量类的对比
项 | 枚举类 | 常量类 |
单例 | 完全单例、线程安全。 枚举类编译后类为:public final class T extends Enum,不允许继承可防止被子类修改。 | 不单例 常量类可被继承修改、增加字段等,容易导致父类的不兼容。 |
性能 | 性能高。 常量值地址唯一,可以用==直接对比 | 性能低 使用常量类时,往往得通过equals去判断两者是否相等。 |
引用类 | 不需重新编译引用类。 枚举类编译时,没有把常量值编译到代码里,即使常量的值发生变化,也不会影响引用常量的类。 | 需要重新编译引用类。 常量类编译时,是直接把常量的值编译到类的二进制代码里,常量的值在升级中变化后,需要重新编译引用常量的类,因为里面存的是旧值。 |
越界 | 不会越界。 编译期间限定类型,不允许发生越界的情况。 | 可能越界。 switch语句支持枚举型,当switch使用int、String类型时,由于值的不稳定性往往会有越界的现象,对于这个的处理往往只能通过if条件筛选以及default模块来处理。 |
枚举与普通类
差别不大。枚举也可以定义变量与方法:
package com.example.a;
enum MyEnum{
FIRST("第一个"),
SECOND("第二个"),
;
private final String description;
MyEnum(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
private String lastName;
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
public class Demo {
public static void main(String[] args) {
MyEnum.FIRST.setLastName("Tony");
System.out.println(MyEnum.FIRST.getLastName());
System.out.println(MyEnum.FIRST.getDescription());
}
}
执行结果
Tony
第一个
枚举与数据库
枚举型可以直接与数据库打交道,我通常使用varchar类型存储,对应的是枚举项的名字。
在下边的例子中,如果某个类中的字段为:private PersonType type; 则其对应的数据库中的值为:"STUDENT"、"TEACHER"。
package com.example.a;
public enum PersonType{
STUDENT("学生"),
TEACHER("教师"),
;
private final String description;
PersonType(String description) {
this.description = description;
}
public String getDesc() {
return description;
}
}
基础示例
一个参数
实例
package com.example.a;
enum PayTypeEnum{
ALIPAY("支付宝"),
WECHAT("微信"),
UNION_PAY("银联"),
;
//这个必须定义,且成员变量的类型及个数必须对应于上边枚举的定义
//枚举标识码(英文描述)
private String description;
//必须提供为私有的,防止外部new对象
PayTypeEnum(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
public class Demo {
public static void main(String[] args){
for (PayTypeEnum value : PayTypeEnum.values()) {
System.out.println("name:" + value.name() + "," + "description:" + value.getDescription());
// 下边这样写结果是一样的
// System.out.println("name:" + value.toString() + "," + "description:" + value.getDescription());
}
}
}
运行结果
name:ALIPAY,desc:支付宝
name:WECHAT,desc:微信
name:UNIONPAY,desc:银联
多个参数
实例
package com.example.a;
interface IEnum{
String getCode();
String getDescription();
}
enum PayTypeEnum implements IEnum{
ALIPAY("ALIPAY", "支付宝"),
WECHAT("WECHAT", "微信"),
UNION_PAY("UNION_PAY", "银联"),
;
//这个必须定义,且成员变量的类型及个数必须对应于上边枚举的定义
//枚举标识码(英文描述)
private final String code;
//枚举标识码(中文描述)
private final String description;
//必须提供,而且是私有的,防止外部new对象
PayTypeEnum(String code, String description) {
this.code = code;
this.description = description;
}
public static String getDescriptionByCode(String code){
for(PayTypeEnum value : PayTypeEnum.values()){
if(value.getCode().equals(code)){
return value.getDescription();
}
}
return null;
}
@Override
public String getCode() {
return this.code;
}
@Override
public String getDescription() {
return this.description;
}
}
public class Demo {
public static void main(String[] args){
System.out.println(PayTypeEnum.getDescriptionByCode(PayTypeEnum.ALIPAY.getCode()));
System.out.println(PayTypeEnum.getDescriptionByCode(PayTypeEnum.WECHAT.getCode()));
}
}
运行结果
支付宝
微信
异常处理应用
异常码枚举
package enums.expection;
import org.apache.commons.lang.StringUtils;
public enum ErrorCodeEnum {
SYS_ERROR(1001, "系统错误,请重试"),
UNKNOWN_ERROR(1002, "未知的系统异常"),
SERVICE_INVOKE_FAIL(1003, "服务调用失败"),
ILLEGAL_ARGS(1004, "参数校验错误"),
;
/**
* 结果码值
*/
private final Integer code;
/**
* 描述
*/
private final String description;
ErrorCodeEnum(Integer code, String description) {
this.code = code;
this.description = description;
}
public static ErrorCodeEnum getByValue(String code) {
for (ErrorCodeEnum result : values()) {
System.out.println(result.ordinal());
if (StringUtils.equals(result.getCode(), code)) {
return result;
}
}
return null;
}
public Integer getCode() {
return code;
}
public String getDescription() {
return description;
}
}
自定义异常
package enums.expection;
import org.apache.commons.lang.StringUtils;
import java.util.HashMap;
import java.util.Map;
public class WangException extends RuntimeException {
/** 错误码枚举*/
private ErrorCodeEnum errorCode;
/**
* 详细错误信息
*/
private Map<String, String> errorMap = new HashMap<String, String>();
/**
* 带参构造器
*/
public WangException(ErrorCodeEnum errorCode) {
super(errorCode.getDesc());
this.setErrorCode(errorCode);
}
/**
* 带参构造器.
*/
public WangException(ErrorCodeEnum errorCode, String message) {
super(StringUtils.isNotBlank(message) ? message : errorCode.getDesc());
this.setErrorCode(errorCode);
}
/**
* 带参构造器
*/
public WangException(ErrorCodeEnum errorCode, Map<String, String> errorMap) {
this(errorCode);
this.errorMap = errorMap;
}
/**
* 带参构造器
*/
public WangException(String message) {
super(message);
this.setErrorCode(ErrorCodeEnum.UNKNOWN_ERROR);
}
/**
* Gets error code.
*/
public ErrorCodeEnum getErrorCode() {
return errorCode;
}
/**
* Sets error code.
*/
public void setErrorCode(ErrorCodeEnum errorCode) {
this.errorCode = errorCode;
}
/**
* Gets error map.
*/
public Map<String, String> getErrorMap() {
return errorMap;
}
/**
* Sets error map.
*/
public void setErrorMap(Map<String, String> errorMap) {
this.errorMap = errorMap;
}
private static String findMessage(Map<String, String> errorMap) {
if (errorMap.isEmpty()) {
return null;
}
return errorMap.values().iterator().next();
}
}
测试类
package enums.expection;
public class Test {
public static void main(String[] args) {
String name="";
int i=0;
try {
if (name == null)
throw new WangException(ErrorCodeEnum.ILLEGAL_ARGS);
if(i==0)
throw new WangException(ErrorCodeEnum.ILLEGAL_ARGS, "参数不能为0");
}catch (WangException e){
e.printStackTrace();
System.out.println("异常码:"+e.getErrorCode().getCode());
System.out.println("异常描述:"+e.getMessage());
}
}
}
高级操作
接口中定义注解
package org.example.a;
interface Color {
enum Green {LIGHT_GREEN, DARK_GREEN}
enum Red {LIGHT_RED, DARK_RED}
}
public class Demo {
public static void main(String[] args) {
System.out.println(Color.Green.DARK_GREEN.ordinal());
}
}
执行结果
1
枚举上使用注解
见:Java--Annotation(注解)--使用/应用/实例_IT利刃出鞘的博客-CSDN博客
实现原理
枚举类
package org.example.a;
public enum Season {
SPRING, SUMMER, AUTUMN, WINTER;
}
反编译代码
public final class Season extends Enum
{
private Season(String s, int i)
{
super(s, i);
}
public static Season[] values()
{
Season at[];
int i;
Season at1[];
System.arraycopy(at = ENUM$VALUES, 0, at1 = new Season[i = at.length], 0, i);
return at1;
}
public static Season valueOf(String s)
{
return (Season)Enum.valueOf(demo/Season, s);
}
public static final Season SPRING;
public static final Season SUMMER;
public static final Season AUTUMN;
public static final Season WINTER;
private static final Season ENUM$VALUES[];
static
{
SPRING = new Season("SPRING", 0);
SUMMER = new Season("SUMMER", 1);
AUTUMN = new Season("AUTUMN", 2);
WINTER = new Season("WINTER", 3);
ENUM$VALUES = (new Season[] {
SPRING, SUMMER, AUTUMN, WINTER
});
}
}
分析
通过反编译后代码可见,该类继承了Enum类,同时final关键字表明这个类不能被继承。
字段都是static类型的,static类型的属性会在类被加载之后被初始化。当一个Java类第一次被真正使用到的时候静态资源被初始化、Java类的加载和初始化过程都是线程安全的。所以,创建一个enum类型是线程安全的。