Java学习笔记 15、枚举类
@[toc]
前言
本篇文章是对枚举类的回炉学习,其中部分内容参考的是尚硅谷的课堂ppt教案,同时对其中知识点进行补充,这里帮尚硅谷打个广告报答一下:尚硅谷_Java零基础教程-java入门必备-适合初学者的全套完整版教程(宋红康主讲)。
博客归类目录见:博客目录索引(持续更新)
一、认识枚举类
当类的对象只有有限个,确定的时,并且需要将其对象定义为一组常量时,建议使用枚举类
,若枚举类只有一个对象则可以作为一种单例模式的实现方式。
- 举例:JDK中的
Tread.State
类中使用了枚举类,有NEW
、RUNNABLE
、BLOCKED
、WAITING
、TIMED_WAITING
、TERMINATED
,它们分别用来表示线程的不同状态。
枚举类可以使用两种方式实现:
JDK1.5
之前需要自定义枚举类。JDK 1.5
新增enum
关键字来用于定义枚举类。
二、自定义枚举类(jdk1.5之前方式)
枚举类的属性介绍:
- 枚举类对象的属性不应该进行改动,应使用
private final
(常量)来修饰。 - 对于使用
private final
的常量对象应该在有参构造器中进行赋值。
自定义枚举类如下:
class Season{
//1、将注解类中的属性设置为private final常量,不能进行改动
private final String SeasonName;
private final String SeasonDesc;
//2、私有构造器,防止外部构造对象
private Season(String seasonName, String seasonDesc) {
SeasonName = seasonName;
SeasonDesc = seasonDesc;
}
public String getSeasonName() {
return SeasonName;
}
public String getSeasonDesc() {
return SeasonDesc;
}
@Override
public String toString() {
return "Season{" +
"SeasonName='" + SeasonName + '\'' +
", SeasonDesc='" + SeasonDesc + '\'' +
'}';
}
//3、提供当前枚举类的多个对象,其修饰符为:public static final,可以被外界获取
public static final Season SPRING = new Season("春天","百花齐放");
public static final Season SUMMER = new Season("夏天","夏日炎炎");
public static final Season AUTUMN = new Season("秋天","秋高气爽");
public static final Season WINTER = new Season("冬天","白雪皑皑");
}
/**
* @ClassName EnumExer
* @Author ChangLu
* @Date 2021/2/21 15:50
* @Description TODO
*/
public class EnumExer {
public static void main(String[] args) {
Season spring = Season.SPRING;
Season summer = Season.SUMMER;
Season autumn = Season.AUTUMN;
Season winter = Season.WINTER;
System.out.println(spring);//Season{SeasonName='春天', SeasonDesc='百花齐放'}
System.out.println(summer);//Season{SeasonName='夏天', SeasonDesc='夏日炎炎'}
System.out.println(autumn);//Season{SeasonName='秋天', SeasonDesc='秋高气爽'}
System.out.println(winter);//Season{SeasonName='冬天', SeasonDesc='白雪皑皑'}
}
}
- 注意其中三个关键点
- 第一个就是属性应该设置为
private final
是不允许外界使用set方法进行赋值的。 - 第二个就是构造器为
private
,外界不能通过构造器来构造枚举类对象。 - 第三个就是提供枚举类对象,权限修饰符为
public static final
应该是能够被外界直接获取使用的。
- 第一个就是属性应该设置为
这是自定义枚举类的方式,一般我们使用jdk1.5
之后的这种方式来创建枚举类。
三、enum定义枚举类(jdk1.5新增)
3.1、使用enum定义枚举类
使用enum
定义的枚举类说明:
- 使用
enum
定义的枚举类默认继承了java.lang.Enum
类,因此不能继承其他类。 - 枚举类的构造器只能使用
private
权限修饰符。 - 枚举类实例在类中显示列出,使用
,
分割;
结尾,可定义多个实例。列出的实例系统会自动添加public static final
修饰。 - 必须在枚举类的第一行声明枚举类对象。
JDK 1.5
中可以在switch
表达式中使用Enum
定义的枚举类的对象作为表达式,case
子句可以直接使用枚举值的名字, 无需添加枚举类作为限定。
enum
定义枚举类如下:
enum Season{
//,分割 ;结尾 这里实际上定义了4个public static final的实例(会自动添加修饰)
//SPRING("春天","百花齐放") =>(相当于) public static final Season SPRING = new Season("春天","百花齐放");
SPRING("春天","百花齐放"),
SUMMER("夏天","夏日炎炎"),
AUTUMN("秋天","秋高气爽"),
WINTER("冬天","白雪皑皑");
private final String SeasonName;
private final String SeasonDesc;
private Season(String seasonName, String seasonDesc) {
SeasonName = seasonName;
SeasonDesc = seasonDesc;
}
public String getSeasonName() {
return SeasonName;
}
public String getSeasonDesc() {
return SeasonDesc;
}
}
public class EnumExer {
public static void main(String[] args) {
Season spring = Season.SPRING;
Season summer = Season.SUMMER;
Season autumn = Season.AUTUMN;
Season winter = Season.WINTER;
System.out.println(spring);//SPRING
System.out.println(summer);//SUMMER
System.out.println(autumn);//AUTUMN
System.out.println(winter);//WINTER
}
}
- 使用
enum
定义时,对于实例需要直接写在类的最前面,若是有多个实例可以使用,分割开。 - 这里输出时使用的是
Enum
类中的toString()
输出的是当前枚举常量的名称。
3.2、认识java.lang.enum类
之前说到使用enum
定义枚举类的会继承java.lang.enum
,看一下该类:
- 实现了
Comparable
接口以及序列化接口。
static static <T extends Enum<T>> T valueOf()
:传递枚举类型的Class对象和枚举常量名称,会得到与参数匹配的枚举常量。String toString()
:默认会得到当前枚举常量的名称。可以通过重写这个方法来使得到的结果更易读。final boolean equals()
:该方法是常量(final
)方法无法重写,在Enum
中是使用==
来比较两个枚举常量是否相同。其存在是为了在Set
、List
和Map
中使用。final int hashCode()
:与equals()
同样是常量方法无法被子类重写。final Class<E> getDeclaringClass()
:得到枚举常量所属枚举类型的Class对象。可以用它来判断两个枚举常量是否属于同一个枚举类型。final String name()
:也是得到当前枚举常量的名称,与toString()
都是返回name
属性。final int ordinal()
:得到当前枚举常量定义时的序列号(从0开始)。final int compareTo()
:这是实现Comparable接口的方法,来比较两个枚举常量的大小(根据定义实例的声明顺序排列)。final Object clone()
:因枚举类型不能被克隆,防止子类实现克隆方法,该方法定义为常量方法,并且直接抛出CloneNotSupportedException
异常。
常用方法介绍:前两个是编译器插入到enum
中的方法并不是默认继承Enum
类获取的方法
values()
:该方法是编译器插入到enum
定义中的static
方法,直接调用枚举类的方法,返回一个你定义的枚举类数组,方便进行遍历该枚举类的常量。valueOf(String str)
:通过传入一个字符串来获取该枚举类的一个枚举实例,必须是枚举类对象的实例名称,否则IllegalArgumentException
异常。toString()
:这是继承Enum类的方法,返回实例名称,尽量要重写它。
提出疑问这两个方法是怎么来的?
- 查阅博客,通过反编译字节码文件认为是实现了
java.lang.annotation.ElementType
中的values()
与valueOf
方法,这个过程是在编译器中自动生成的。
测试编译器中生成的两个方法:
enum Code{
RED,BLUE,YELLOW;
}
public class Test {
public static void main(String[] args) {
//测试Code枚举类的values()方法
Code[] values = Code.values();
for (Code value : values) {
System.out.println(value);
}
//RED
//BLUE
//RED
//测试valueOf()方法
System.out.println(Code.valueOf("RED"));//RED
}
}
IDEA
中悬浮到这两个方法时的介绍。
我们自己进行反编译字节码查看一下下面这个枚举类
enum Code{
RED,BLUE,YELLOW;
}
首先使用javac 类.java
编译成字节码文件(.class后缀),之后使用javap Code
进行反编译该字节码文件:
之后再使用javap -v Code
来查看Code.class字节码结构:
-
这里看到是继承的
Enum
,查阅大佬博客推测出实际上是继承了ElementType
,我们去看一下Enum
类的定义-
//这里泛型为E extends Enum<E> 表示该泛型必须是Enum的子类 public abstract class Enum<E extends Enum<E>>
-
ElementType
是注解,并且是Enum
类的子类。
先暂且这么记着,对于我现在的水平不能窥探到更深的地步,日后再来深入挖掘。
3.3、枚举类实现接口
现有一个接口如下:
interface Info{
void show();
}
直接在enum枚举类中实现抽象方法
//实现该接口
enum Season implements Info{
SPRING("春天","百花齐放"),
SUMMER("夏天","夏日炎炎"),
AUTUMN("秋天","秋高气爽"),
WINTER("冬天","白雪皑皑");
private String SeasonName;
private String SeasonDesc;
private Season(String seasonName, String seasonDesc) {
SeasonName = seasonName;
SeasonDesc = seasonDesc;
}
//直接实现抽象方法show()
@Override
public void show() {
System.out.println("这里是描述四个季节的枚举类");
}
}
public class EnumExer {
public static void main(String[] args) {
Season.SPRING.show();//这里是描述四个季节的枚举类
Season.SUMMER.show();//这里是描述四个季节的枚举类
}
}
- 可以看到多个实例调用的都是同一个
show()
方法。
枚举类中实例重写show()方法
enum Season implements Info{
//这里对该实例进行了方法重写(应该是重写了Season该类的show()方法)
SPRING("春天","百花齐放"){
@Override
public void show() {
System.out.println("SPRING实例的show()方法调用了....");
}
},
SUMMER("夏天","夏日炎炎"){
@Override
public void show() {
System.out.println("SUMMER实例的show()方法调用了....");
}
},
AUTUMN("秋天","秋高气爽"),
WINTER("冬天","白雪皑皑");
private String SeasonName;
private String SeasonDesc;
private Season(String seasonName, String seasonDesc) {
SeasonName = seasonName;
SeasonDesc = seasonDesc;
}
@Override
public void show() {
System.out.println("这里是描述四个季节的枚举类");
}
}
public class EnumExer {
public static void main(String[] args) {
Season.SPRING.show();//SPRING实例的show()方法调用了....
Season.SUMMER.show();//SUMMER实例的show()方法调用了....
Season.AUTUMN.show();//这里是描述四个季节的枚举类
}
}
- 可以看到这里是在对应实例后添加{},其中重写了
show()
方法,之后我们调用实例的方法就是指定其重写的方法。
总结:
- 枚举类可以实现一个或多个接口,统一实现方法每个枚举实例都可以进行调用。
- 继承接口方式的使用方法有如上两种方式。
四、enum相关的类
Class类与enum相关
isEnum()
:能够判断该Class是否为枚举类。
与enum相关的工具类:EnumSet与EnumMap
EnumSet
:JDK1.5引入,该类设计充分考虑了速度因素,可以作为Enum的替代者,效率更高。
EnumMap
:JDK1.5引入,是一个特殊的Map
,其key键是一个enum
,可以进行快速检索。
暂且就先记录一下,深入使用内容后序若是使用到了进行补充。
参考文章
[1]. Java enum的用法详解
- 点赞
- 收藏
- 关注作者
评论(0)