JAVA 枚举相关知识汇总

Java 枚举

知识点

概念

enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性。

在Java中,被 enum 关键字修饰的类型就是枚举类型。形式如下:

enum Color { RED, GREEN, BLUE }

如果枚举不添加任何方法,枚举值默认为从0开始的有序数值。以 Color 枚举类型举例,它的枚举常量依次为 RED:0,GREEN:1,BLUE:2

枚举的好处:可以将常量组织起来,统一进行管理。

枚举的典型应用场景:错误码、状态机等。

枚举类型的本质

尽管 enum 看起来像是一种新的数据类型,事实上,enum是一种受限制的类,并且具有自己的方法。

创建enum时,编译器会为你生成一个相关的类,这个类继承自 java.lang.Enum

java.lang.Enum类声明

public abstract class Enum<E extends Enum<E>>
 implements Comparable<E>, Serializable { ... }

枚举的方法

在enum中,提供了一些基本方法:

values():返回 enum 实例的数组,而且该数组中的元素严格保持在 enum 中声明时的顺序。

name():返回实例名。

ordinal():返回实例声明时的次序,从0开始。

getDeclaringClass():返回实例所属的 enum 类型。

equals() :判断是否为同一个对象。

可以使用 == 来比较enum实例。

此外,java.lang.Enum实现了Comparable Serializable 接口,所以也提供 compareTo() 方法。

例:展示enum的基本方法

public class EnumMethodDemo {
 enum Color {RED, GREEN, BLUE;}
 enum Size {BIG, MIDDLE, SMALL;}
 public static void main(String args[]) {
 System.out.println("=========== Print all Color ===========");
 for (Color c : Color.values()) {
  System.out.println(c + " ordinal: " + c.ordinal());
 }
 System.out.println("=========== Print all Size ===========");
 for (Size s : Size.values()) {
  System.out.println(s + " ordinal: " + s.ordinal());
 }

 Color green = Color.GREEN;
 System.out.println("green name(): " + green.name());
 System.out.println("green getDeclaringClass(): " + green.getDeclaringClass());
 System.out.println("green hashCode(): " + green.hashCode());
 System.out.println("green compareTo Color.GREEN: " + green.compareTo(Color.GREEN));
 System.out.println("green equals Color.GREEN: " + green.equals(Color.GREEN));
 System.out.println("green equals Size.MIDDLE: " + green.equals(Size.MIDDLE));
 System.out.println("green equals 1: " + green.equals(1));
 System.out.format("green == Color.BLUE: %b\n", green == Color.BLUE);
 }
}

输出

=========== Print all Color ===========
RED ordinal: 0
GREEN ordinal: 1
BLUE ordinal: 2
=========== Print all Size ===========
BIG ordinal: 0
MIDDLE ordinal: 1
SMALL ordinal: 2
green name(): GREEN
green getDeclaringClass(): class org.zp.javase.enumeration.EnumDemo$Color
green hashCode(): 460141958
green compareTo Color.GREEN: 0
green equals Color.GREEN: true
green equals Size.MIDDLE: false
green equals 1: false
green == Color.BLUE: false

枚举的特性

枚举的特性,归结起来就是一句话:

除了不能继承,基本上可以将 enum 看做一个常规的类。

但是这句话需要拆分去理解,让我们细细道来。

枚举可以添加方法

在概念章节提到了,枚举值默认为从0开始的有序数值 。那么问题来了:如何为枚举显示的赋值。

Java 不允许使用 = 为枚举常量赋值

如果你接触过C/C++,你肯定会很自然的想到赋值符号 = 。在C/C++语言中的enum,可以用赋值符号=显示的为枚举常量赋值;但是 ,很遗憾,Java 语法中却不允许使用赋值符号 = 为枚举常量赋值。

例:C/C++ 语言中的枚举声明

typedef enum{
 ONE = 1,
 TWO,
 THREE = 3,
 TEN = 10
} Number;

枚举可以添加普通方法、静态方法、抽象方法、构造方法

Java 虽然不能直接为实例赋值,但是它有更优秀的解决方案:为 enum 添加方法来间接实现显示赋值。

创建 enum 时,可以为其添加多种方法,甚至可以为其添加构造方法。

注意一个细节:如果要为enum定义方法,那么必须在enum的最后一个实例尾部添加一个分号。此外,在enum中,必须先定义实例,不能将字段或方法定义在实例前面。否则,编译器会报错。

例:全面展示如何在枚举中定义普通方法、静态方法、抽象方法、构造方法

public enum ErrorCode {
 OK(0) {
 public String getDescription() {
  return "成功";
 }
 },
 ERROR_A(100) {
 public String getDescription() {
  return "错误A";
 }
 },
 ERROR_B(200) {
 public String getDescription() {
  return "错误B";
 }
 };

 private int code;

 // 构造方法:enum的构造方法只能被声明为private权限或不声明权限
 private ErrorCode(int number) { // 构造方法
 this.code = number;
 }
 public int getCode() { // 普通方法
 return code;
 } // 普通方法
 public abstract String getDescription(); // 抽象方法
 public static void main(String args[]) { // 静态方法
 for (ErrorCode s : ErrorCode.values()) {
  System.out.println("code: " + s.getCode() + ", description: " + s.getDescription());
 }
 }
}

注:上面的例子并不可取,仅仅是为了展示枚举支持定义各种方法。下面是一个简化的例子

例:一个错误码枚举类型的定义

本例和上例的执行结果完全相同。

public enum ErrorCodeEn {
 OK(0, "成功"),
 ERROR_A(100, "错误A"),
 ERROR_B(200, "错误B");

 ErrorCodeEn(int number, String description) {
 this.code = number;
 this.description = description;
 }
 private int code;
 private String description;
 public int getCode() {
 return code;
 }
 public String getDescription() {
 return description;
 }
 public static void main(String args[]) { // 静态方法
 for (ErrorCodeEn s : ErrorCodeEn.values()) {
  System.out.println("code: " + s.getCode() + ", description: " + s.getDescription());
 }
 }
}

枚举可以实现接口

enum 可以像一般类一样实现接口。

同样是实现上一节中的错误码枚举类,通过实现接口,可以约束它的方法。

public interface INumberEnum {
 int getCode();
 String getDescription();
}

public enum ErrorCodeEn2 implements INumberEnum {
 OK(0, "成功"),
 ERROR_A(100, "错误A"),
 ERROR_B(200, "错误B");

 ErrorCodeEn2(int number, String description) {
 this.code = number;
 this.description = description;
 }

 private int code;
 private String description;

 @Override
 public int getCode() {
 return code;
 }

 @Override
 public String getDescription() {
 return description;
 }
}

枚举不可以继承

enum 不可以继承另外一个类,当然,也不能继承另一个 enum 。

因为 enum 实际上都继承自 java.lang.Enum 类,而 Java 不支持多重继承,所以 enum 不能再继承其他类,当然也不能继承另一个 enum。

枚举的应用场景

组织常量

在JDK1.5 之前,在Java中定义常量都是public static final TYPE a; 这样的形式。有了枚举,你可以将有关联关系的常量组织起来,使代码更加易读、安全,并且还可以使用枚举提供的方法。

枚举声明的格式

注:如果枚举中没有定义方法,也可以在最后一个实例后面加逗号、分号或什么都不加。

下面三种声明方式是等价的:

enum Color { RED, GREEN, BLUE }
enum Color { RED, GREEN, BLUE, }
enum Color { RED, GREEN, BLUE; }

switch 状态机

我们经常使用switch语句来写状态机。JDK7以后,switch已经支持 int、char、String、enum 类型的参数。这几种类型的参数比较起来,使用枚举的switch代码更具有可读性。

enum Signal {RED, YELLOW, GREEN}

public static String getTrafficInstruct(Signal signal) {
 String instruct = "信号灯故障";
 switch (signal) {
 case RED:
  instruct = "红灯停";
  break;
 case YELLOW:
  instruct = "黄灯请注意";
  break;
 case GREEN:
  instruct = "绿灯行";
  break;
 default:
  break;
 }
 return instruct;
}

组织枚举

可以将类型相近的枚举通过接口或类组织起来。

但是一般用接口方式进行组织。

原因是:Java接口在编译时会自动为enum类型加上public static修饰符;Java类在编译时会自动为 enum 类型加上static修饰符。看出差异了吗?没错,就是说,在类中组织 enum,如果你不给它修饰为 public,那么只能在本包中进行访问。

例:在接口中组织 enum

public interface Plant {
 enum Vegetable implements INumberEnum {
 POTATO(0, "土豆"),
 TOMATO(0, "西红柿");

 Vegetable(int number, String description) {
  this.code = number;
  this.description = description;
 }

 private int code;
 private String description;

 @Override
 public int getCode() {
  return 0;
 }

 @Override
 public String getDescription() {
  return null;
 }
 }

 enum Fruit implements INumberEnum {
 APPLE(0, "苹果"),
 ORANGE(0, "桔子"),
 BANANA(0, "香蕉");

 Fruit(int number, String description) {
  this.code = number;
  this.description = description;
 }

 private int code;
 private String description;

 @Override
 public int getCode() {
  return 0;
 }

 @Override
 public String getDescription() {
  return null;
 }
 }
}

例:在类中组织 enum

本例和上例效果相同。

public class Plant2 {
 public enum Vegetable implements INumberEnum {...} // 省略代码
 public enum Fruit implements INumberEnum {...} // 省略代码
}

策略枚举

EffectiveJava中展示了一种策略枚举。这种枚举通过枚举嵌套枚举的方式,将枚举常量分类处理。

这种做法虽然没有switch语句简洁,但是更加安全、灵活。

例:EffectvieJava中的策略枚举范例

enum PayrollDay {
 MONDAY(PayType.WEEKDAY), TUESDAY(PayType.WEEKDAY), WEDNESDAY(
  PayType.WEEKDAY), THURSDAY(PayType.WEEKDAY), FRIDAY(PayType.WEEKDAY), SATURDAY(
  PayType.WEEKEND), SUNDAY(PayType.WEEKEND);

 private final PayType payType;

 PayrollDay(PayType payType) {
 this.payType = payType;
 }

 double pay(double hoursWorked, double payRate) {
 return payType.pay(hoursWorked, payRate);
 }

 // 策略枚举
 private enum PayType {
 WEEKDAY {
  double overtimePay(double hours, double payRate) {
  return hours <= HOURS_PER_SHIFT ? 0 : (hours - HOURS_PER_SHIFT)
   * payRate / 2;
  }
 },
 WEEKEND {
  double overtimePay(double hours, double payRate) {
  return hours * payRate / 2;
  }
 };
 private static final int HOURS_PER_SHIFT = 8;

 abstract double overtimePay(double hrs, double payRate);

 double pay(double hoursWorked, double payRate) {
  double basePay = hoursWorked * payRate;
  return basePay + overtimePay(hoursWorked, payRate);
 }
 }
}

测试

System.out.println("时薪100的人在周五工作8小时的收入:" + PayrollDay.FRIDAY.pay(8.0, 100));
System.out.println("时薪100的人在周六工作8小时的收入:" + PayrollDay.SATURDAY.pay(8.0, 100));

EnumSet和EnumMap

Java 中提供了两个方便操作enum的工具类——EnumSet 和 EnumMap。

EnumSet 是枚举类型的高性能 Set 实现。它要求放入它的枚举常量必须属于同一枚举类型。

EnumMap 是专门为枚举类型量身定做的 Map 实现。虽然使用其它的 Map 实现(如HashMap)也能完成枚举类型实例到值得映射,但是使用 EnumMap 会更加高效:它只能接收同一枚举类型的实例作为键值,并且由于枚举类型实例的数量相对固定并且有限,所以 EnumMap 使用数组来存放与枚举类型对应的值。这使得 EnumMap 的效率非常高。

// EnumSet的使用
System.out.println("EnumSet展示");
EnumSet<ErrorCodeEn> errSet = EnumSet.allOf(ErrorCodeEn.class);
for (ErrorCodeEn e : errSet) {
 System.out.println(e.name() + " : " + e.ordinal());
}

// EnumMap的使用
System.out.println("EnumMap展示");
EnumMap<StateMachine.Signal, String> errMap = new EnumMap(StateMachine.Signal.class);
errMap.put(StateMachine.Signal.RED, "红灯");
errMap.put(StateMachine.Signal.YELLOW, "黄灯");
errMap.put(StateMachine.Signal.GREEN, "绿灯");
for (Iterator<Map.Entry<StateMachine.Signal, String>> iter = errMap.entrySet().iterator(); iter.hasNext();) {
 Map.Entry<StateMachine.Signal, String> entry = iter.next();
 System.out.println(entry.getKey().name() + " : " + entry.getValue());
}

以上就是JAVA 枚举相关知识汇总的详细内容,更多关于JAVA 枚举的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java枚举类使用场景及实例解析

    为什么要用枚举类 什么场景会用到枚举,比如在表示一周的某一天,一年中的四季,这样一组常量的时候我们会用到枚举.在Java引入枚举类之前常用一组int常量来表示枚举,这种方式称为int枚举模式(int enum pattern). private static final int MONDAY = 1; private static final int TUESDAY = 2; private static final int WEDNESDAY = 3; private static final

  • 扒一扒 Java 中的枚举类型

    前言 在 Java 中, 枚举, 也称为枚举类型, 其是一种特殊的数据类型, 它使得变量能够称为一组预定义的常量. 其目的是强制编译时类型安全. 枚举类更加直观,类型安全.使用常量会有以下几个缺陷: 1. 类型不安全.若一个方法中要求传入季节这个参数,用常量的话,形参就是int类型,开发者传入任意类型的int类型值就行,但是如果是枚举类型的话,就只能传入枚举类中包含的对象. 2. 没有命名空间.开发者要在命名的时候以SEASON_开头,这样另外一个开发者再看这段代码的时候,才知道这四个常量分别代

  • Java实现转跳不同系统使用枚举加switch的方式示例

    因有个判断需要处理不同系统类型跳转不同系统.考虑用switch + 枚举的方式. 具体使用案例如下: package com.b2b.common.constant; import com.base.utils.base.StringUtils; /** * 系统类型枚举 * @author shijing */ public enum SystemType { ERP(0,"ERP"), ORDER_PLATFORM(1,"订货平台"), PERSONAL(2,&

  • java枚举类的属性、方法和构造方法应用实战

    本文实例讲述了java枚举类的属性.方法和构造方法应用.分享给大家供大家参考,具体如下: 一 点睛 枚举类也是一种类,只是它是一种比较特殊的类,因此它一样可以使用属性和方法. 枚举类通常应该设计成不可变类,也就说它的属性值不应该允许改变,这样会更安全,而且代码更加简洁.为此,我们应该将枚举类的属性都使用private final修饰. 一旦为枚举类显式定义了带参数的构造器,则列出枚举值时也必须对应地传入参数. 二 简单枚举类实战 1 代码 Gender.java public enum Gend

  • Java手动方式创建枚举类示例

    本文实例讲述了Java手动方式创建枚举类.分享给大家供大家参考,具体如下: 一 点睛 可以采用如下设计方式手动创建枚举类 通过private将构造器隐藏起来. 把这个类的所有可能实例都使用public static final属性来保存. 如果有必要,可以提供一些静态方法,允许其他程序根据特定参数来获取与之匹配实例. 二 代码 1 Season.java public class Season { // 把Season类定义成不可变的,将其成员变量也定义成final的 private final

  • 优雅地在Java应用中实现全局枚举处理的方法

    背景描述 为了表达某一个属性,具备一组可选的范围,我们一般会采用两种方式.枚举类和数据字典,两者具有各自的优点.枚举类写在Java代码中,方便编写相应的判断逻辑,代码可读性高,枚举类中的属性是可提前预估和确定的.数据字典,一般保存在数据库,不便于编写判断和分支逻辑,因为数据如果有所变动,那么对应的代码逻辑很有可能失效,强依赖数据库数据的正确性,数据字典中对应的属性对业务影响并不大,日常开发中常用做分类,打标签使用,属性的多少无法估计. 目前基本上没有一个很好的全局处理枚举类的方案,所以我就自己综

  • Java的枚举enum示例详解

    一. 什么是枚举 枚举是一种数据类型,具有集合的一些特点,可以存放多个元素,但存储对象有限且固定,枚举也有比较常见的使用场景,如我们需要表达性别(男.女),颜色(红.黄.蓝),星期(星期一.星期二...星期日),四季(春.夏.秋.冬),地理位置(东.西.南.北),方向(前.后.左.右)等,这些场景都非常适合枚举. 二. 定义枚举 java中使用enum来定义枚举,和class,interface具有同样的等级,(注意是enum,而不是Enum),定义枚举可以有两种情况 第一种:默认构造器(空构造

  • JAVA 枚举相关知识汇总

    Java 枚举 知识点 概念 enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性. 在Java中,被 enum 关键字修饰的类型就是枚举类型.形式如下: enum Color { RED, GREEN, BLUE } 如果枚举不添加任何方法,枚举值默认为从0开始的有序数值.以 Color 枚举类型举例,它的枚举常量依次为 RED:0,GREEN:1,BLUE:2. 枚举的好处:可以将常量组织起来,统一进行管理. 枚举的典型应用场景:错误码.状态机等. 枚举类型的本质

  • JAVA内存空间相关知识汇总

    Java内存分配与管理是Java的核心技术之一,之前我们曾介绍过Java的内存管理与内存泄露以及Java垃圾回收方面的知识,今天我们再次深入Java核心,详细介绍一下Java在内存分配方面的知识.一般Java在内存分配时会涉及到以下区域: ◆寄存器:我们在程序中无法控制 ◆栈:存放基本类型的数据和对象的引用,但对象本身不存放在栈中,而是存放在堆中 ◆堆:存放用new产生的数据 ◆静态域:存放在对象中用static定义的静态成员 ◆常量池:存放常量 ◆非RAM存储:硬盘等永久存储空间 Java内存

  • JAVA 线程通信相关知识汇总

    两个线程之间的通信 多线程环境下CPU会随机的在线程之间进行切换,如果想让两个线程有规律的去执行,那就需要两个线程之间进行通信,在Object类中的两个方法wait和notify可以实现通信. wait方法可以使当前线程进入到等待状态,在没有被唤醒的情况下,线程会一直保持等待状态. notify方法可以随机唤醒单个在等待状态下的线程. 来实现这样的一个功能: 让两个线程交替在控制台输出一行文字 定义一个Print类,有两个方法print1和print2,分别打印一行不同的内容 package c

  • Java之SSM中bean相关知识汇总案例讲解

    bean 的生命周期 对象创建 实例化Bean对象,默认选择无参构造方法,如果只有一个有参构造那么调用有参构造,如果只有多个有参构造那么报错,除非其中一个有参构造添加了@AutoWired注解: 设置Bean的属性: 依赖注入以及判断是否实现了Aware相关接口(BeanNameAware, BeanFactoryAware, ApplicationContextAware) 如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用BeanPostProcessor.pos

  • JAVA注解相关知识总结

    注解的概念 java注解: 比较官方的说法: 从JDK5开始,Java增加对元数据的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,这些标记可以在编译,类加载,运行时被读取,并执行相应的处理.通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息. 注解,可以看作是对 一个 类/方法 的一个扩展的模版,每个 类/方法 按照注解类中的规则,来为 类/方法 注解不同的参数,在用到的地方可以得到不同的 类/方法 中注解的各种参数与值. 说说我的理解 注解

  • java类加载相关知识总结

    类加载器 类加载器作用 负责将.class文件(存储的物理文件)加载到内存中 类加载器过程 加载:通过全类名获取这个类准备用流传输,加载进内存,加载完毕创建一个Class对象 链接 验证:确保Class文件字节流中包含的信息符合当前虚拟机的要求,并且不会危害虚拟机自身安全 (文件中的信息是否符合虚拟机规范有没有安全隐患)准备:负责为类的类变量(被static修饰的变量)分配内存,并设置默认初始化值 (初始化静态变量)解析:将类的二进制数据流中的符号引用替换为直接引用 (本类中如果用到了其他类,此

  • 你肯定能看懂的Java IO相关知识总结

    一.IO底层是怎么回事? 操作系统就是管家,电脑的设备就是资源,如果进程先要操作资源,必须要进行系统调用,有操作系统去处理,然后再返回给进程,这样的代理模式是不是很常见?因此app 就是你写的程序,资源就是硬盘或者其他的设备,io就是进行的系统调用. 为了保证操作系统的稳定性和安全性,一个进程的地址空间划分为 用户空间(User space) 和 内核空间(Kernel space ) .像我们平常运行的应用程序都是运行在用户空间,只有内核空间才能进行系统态级别的资源有关的操作,比如如文件管理.

  • 详解java注解相关知识

    定义 1.如果注解中有属性,那么必须给属性赋值. package com.lxc.Test; // 定义一个注解 public @interface Annotation { String name(); // 看似name像一个方法,实际上我们把name称为属性 } 使用上边注解: package com.lxc.Test; public class Test { @Annotation(name="lxc") public void test() { } } 2.如果注解中有属性,

  • Java内存模型知识汇总

    为什么要有内存模型 在介绍Java内存模型之前,先来看一下到底什么是计算机内存模型,然后再来看Java内存模型在计算机内存模型的基础上做了哪些事情.要说计算机的内存模型,就要说一下一段古老的历史,看一下为什么要有内存模型. 内存模型,英文名Memory Model,他是一个很老的老古董了.他是与计算机硬件有关的一个概念.那么我先给你介绍下他和硬件到底有啥关系. CPU和缓存一致性 我们应该都知道,计算机在执行程序的时候,每条指令都是在CPU中执行的,而执行的时候,又免不了要和数据打交道.而计算机

  • JSON相关知识汇总

    JSON:JavaScript 对象表示法(JavaScript Object Notation) JSON 语法规则 数据在名称/值对中 数据由逗号分隔 花括号保存对象 方括号保存数组 JSON有6种类型的值: 对象.数组.字符串.数字.布尔值.null JSON对象是一个容纳"名/值"对的无序集合 名字:任意字符串 值:任意类型的JSON值,包括数组和对象(对象中可以嵌入对象) 注:JSON字符串必须使用双引号(单引号会报错) 一.对象 javascript中创建字面量: var

随机推荐