关键字enum可以将一组具名的值的有限集合创建为一种新的类型,就是枚举类型。枚举类型是Java 1.5新增的特性,这是一个非常有用的特性。
Enum
在这一小部分,我们将探讨枚举的最基本的用法。首先我们必须要明白一点:enum是一个常规类型,只不过它还有一些限制。定义枚举类型很简单,使用enum关键字把所有的值组织起来,就像下面一样:
enum Season {SPRING,SUMMER,FULL,WINTER}
Season拥有四个实例,在一般的命名规范中,通常用大写的字母表示枚举的实例。枚举类型的实例是有序的,每个实例都有一个对应的序号,从0开始,由于enum天然的有序性,可以在switch()语句中使用枚举示例,这样语义更清晰。在创建enum时,编译器会自动生成一个相关的类,这个类继承自java.lang.Enum,Enum是一个普通类,它提供了一些方法,其中有几个是需要我们关注的:
public final int ordinal():返回枚举常量的序号,从0开始,也就是SPRING的序号是0,SUMMER是1,.....
public static <T extends Enum<T>> T valueOf(Class<T> enumType,String name):将给定的name转换成对应枚举类的实例,name必须要与枚举类中的常量完全匹配,它的实现方式大概是这样:在Enum的内部有一个方法,它把枚举的名称和枚举常量组成一个Map,调用valueOf()方法时,就是去Map中get(name);
出了上面的两个方法比较重要外,它还两个比较诡异的方法,待会再解释一下这两个方法:
public static T[] values():返回枚举的所有常量
public static <T extends Enum<T>> T valueOf(String name):将给定的字符串转换成枚举常量,和valueOf(Class<T> enumType,String name)方法类似。
enum中的方法
enum可以添加构造方法,还可以添加自定义的方法,还可以覆盖父类中的方法,所有的这一切都和普通的类一样,只不过会有一些小限制,还是以Season为例,演示enum中的基本用法
package com.think.enumeration;
public enum Season {
//Java要求必须先定义枚举实例,
SPRING(10,20),
SUMMER(20,32),
FULL(10,20),
//这就是哈尔滨的真实写照
WINTER(-40,-5);//注意这个分号,比不可少
private double lowTemp;
private double highTemp;
//一旦enum定义结束,编译器就不允许我们再使用
//其构造器来创建任何实例了,所以即使不是private也没关系
private Season(double low,double high) {
lowTemp = low;
highTemp = high;
}
//自定义的方法,就像在普通的类中一样
public void setLow(double low) {
this.lowTemp = low;
}
//还可以覆盖父类中的方法
@Override
public String toString() {
return "(" + lowTemp + "," + highTemp + ")";
}
//甚至还可以有main方法
public static void main(String[] args) {
for(Season e : Season.values()) {
if(e == SPRING)
e.setLow(-10);
System.out.println(e);
}
}
}
我们一定要抓住enum的本质:
它是一组常量的集合。所以很多限制都是为了确保“常量性”,比如在定义枚举类时,必须先定义enum,它的构造方法在定义enum实例结束后就不能使用。出了围绕常量性的限制之外,其他的语法与普通类无异,我们可以添加普通方法,可以覆盖父类方法等。在所有的特性中,最具特色的要数
常量相关方法。
在enum中除了给enum类型添加方法之外,每个实例还可以有自己的方法,这样的方法叫做常量相关方法:对于同一个方法,不同的实例可以实现自己的行为。这样甚至有了多态性。实现常量相关的方法时,可以将一个方法实现成抽象方法,每个实例提供具体实现;也可以把方法实现成普通方法,每个实例根据需求,选择是否覆盖该方法,示例如下:
public enum ConstantSpecificMethod {
MALE {
//常量相关
public String getSex() {
return "male";
}
//覆盖公共方法
public void f() {
System.out.println("male and male and ");
}
},
FEMALE {
@Override
public String getSex() {
return "female";
}
};
//将方法定义为抽象方法
abstract public String getSex();
//提供公有的实现,实例可以考虑是否覆盖
public void f() {
System.out.println("nothing else");
}
}
对于abstract方法,每个实例必须提供具体实现,对于提供的默认实现,每个实例课根据实际选择是否覆盖。通过常量相关方法,使枚举实例间具有了多态性,但是枚举实例毕竟不是class类型。
编译器的动作
编译器会为enum类型生成class文件,相应的enum类自动继承Enum<T>,这是编译器的常规处理。在前面我们提到了enum类型有values()方法和只有一个参数的valueOf()方法,但是遍查API文档,在Enum类中并没有发现这两个方法,而在前面的例子中我们又确确实实的使用了values()方法,这是怎么一回事呢?下面是根据前面的Season的class文件反编译的结果,选择其中的一部分:
/**
* 下面是编译器为我们生成的的对应的类
* 类被标记为final,这意味着它不可被继承
* 自动继承Enum<T>,Enum中的所有方法它都可以使用,但是它不能再继承其他类了
*/
public final class com.think.enumeration.Season extends java.lang.Enum<com.think.enumeration.Season> {
//所有的实例都被实现为final的
public static final com.think.enumeration.Season SPRING;
public static final com.think.enumeration.Season SUMMER;
public static final com.think.enumeration.Season FULL;
public static final com.think.enumeration.Season WINTER;
static {};
Code:
0: new #1 // class com/think/enumeration/Season
3: dup
4: ldc #18 // String SPRING
6: iconst_0
7: ldc2_w #19 // double 10.0d
10: ldc2_w #21 // double 20.0d
13: invokespecial #23 // Method "<init>":(Ljava/lang/String;IDD)V
16: putstatic #27 // Field SPRING:Lcom/think/enumeration/Season;
........
76: iconst_4
77: anewarray #1 // class com/think/enumeration/Season
80: dup
81: iconst_0
82: getstatic #27 // Field SPRING:Lcom/think/enumeration/Season;
85: aastore
86: dup
87: iconst_1
........
107: return
//编译器为我们提供的方法
public static com.think.enumeration.Season[] values();
Code:
0: getstatic #44 // Field ENUM$VALUES:[Lcom/think/enumeration/Season;
3: dup
4: astore_0
5: iconst_0
6: aload_0
7: arraylength
8: dup
9: istore_1
10: anewarray #1 // class com/think/enumeration/Season
13: dup
14: astore_2
15: iconst_0
16: iload_1
17: invokestatic #110 // Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V
20: aload_2
21: areturn
//编译器为我们提供的方法
public static com.think.enumeration.Season valueOf(java.lang.String);
Code:
0: ldc #1 // class com/think/enumeration/Season
2: aload_0
//实际上是调用Enum.valueOf(Class enumType,String name)方法,只不过第一个参数默认是本枚举类型
3: invokestatic #116 // Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum;
6: checkcast #1 // class com/think/enumeration/Season
9: areturn
}
通过上面的代码,我们可以发现:
(1)编译器自动的把对应的类设置为final,这样它就不能有子类
(2)编译器自动的使对应的类继承子Enum<T>,这样它就不能再继承其他的类,同时可以使用Enum中的方法
(3)Season实例的初始化在一个静态代码块中执行,这一点很重要,这意味这枚举类的实现是在类加载的初始化阶段进行的,一旦把一个枚举类加载到JVM中后,就不能改变枚举类的实例,而且在类加载的初始化阶段,JVM会确保初始化的安全,不会存在多线程的问题。所以在使用单例模式时,把单例类实现成枚举类,其中只有一个实例是一个非常好的手段。
(4)每个实例都是final的
(5)编译器为我们添加了values()方法,它返回此枚举的所有实例;还添加了只有一个参数的valueOf(String name)方法,它其实是调用Enum的valueOf()方法,只不过把该枚举类对应的Class对象传递过去作为第一个参数。也就是如果把一个枚举的实例转换为Enum类型,那么是不可以使用values()方法的,这个时候可以通过Class类的getEnumConstants()方法
Enum e = Season.SPRING;
//不能调用values()方法
//e.values()
//可以使用getEnumConstants()
e.getClass().getEnumConstants()
以上就是枚举的基本用法,枚举是一项很有用的特性,由于它天然的有序性,它可以在很多方面发挥作用,同时使用枚举在构造程序时,结构清晰,语义清晰。
转载请注明出处:喻红叶《Java枚举》
分享到:
相关推荐
Java枚举类型(Enum)是Java SE 5.0引入的一种新的数据类型,它为开发者提供了更为强大且安全的方式来表示一组常量。枚举在Java中不仅是一个类,还是一种特殊的类型,允许我们定义自己的常量集合。接下来,我们将...
Java枚举类型是Java语言中的一种特殊的类,用于定义一组固定的常量集合。它在Java中扮演着重要的角色,提供了一种安全、类型化的常量表示方式,比传统的final static变量更具有优势。理解Java枚举类型对于编写高质量...
总结起来,Java枚举类型是一个强大的工具,它可以替代`static final`常量来表示一组固定的值,提供类型安全、易于维护的代码。通过枚举,我们可以更方便地管理常量,减少错误,并增加代码的灵活性。枚举是Java中一个...
Java枚举类型是Java语言中一种特殊的类,用于定义固定的常量集合,它提供了一种安全、类型化的方式来表示一组有限的值。枚举在Java中被引入为一个完整的类型,不同于C++中的枚举,这使得Java枚举更加强大且易于使用...
### Java枚举类型详解 #### 一、引言 在Java编程语言中,枚举(Enum)作为一种重要的数据类型,在程序设计中扮演着不可或缺的角色。本文将深入探讨Java枚举类型的特性和用法,并通过具体实例说明其优势所在。枚举...
下面我们将深入探讨Java枚举类型的常见用法。 首先,枚举类型在本质上等同于定义了一组静态常量。创建枚举类型的语法如下: ```java public enum Belle { para1, para2, para3, para4; } ``` 这会创建一个名为`...
全面掌握 Java 枚举类型(enum type) Java 枚举类型是一种特殊的数据类型,它可以取有限个数的明确值。枚举类型的引入解决了 int 枚举模式和 String 枚举模式的缺点,提供了类型安全性、可读性和性能等优势。 ...
一个关于JAVA枚举类型的MHT文件,包含JAVA枚举类型的用法,以及JDK版本的问题。
在本压缩包中,"Java 枚举类型案例"可能包含了多个示例,以帮助我们深入理解Java枚举类型的使用。 1. **枚举的定义** 在Java中,枚举是通过关键字`enum`来定义的。例如,创建一个表示星期的枚举类型: ```java ...
### Java 枚举类型 enum 的使用详解 #### 一、枚举类型概述 在 Java 中,枚举(enum)是一种特殊的类,它被用来表示一组固定的常量值。枚举类型自 JDK 1.5 开始引入,为开发者提供了一种更加安全、简洁的方式来...
以下是关于Java枚举类型的详细知识点: 1. **枚举定义**: - 枚举类型通过`enum`关键字来定义,例如`public enum Color {RED, BLUE, BLACK, YELLOW, GREEN}`。 - 枚举实际上是`java.lang.Enum`类的子类,这意味着...
JAVA枚举类型[归纳].pdf
本篇文章将深入探讨Java枚举的特性、用法以及如何在实际开发中充分利用它们。 一、枚举的基本用法 1. 声明枚举类型: ```java public enum Color { RED, GREEN, BLUE } ``` 在这里,`Color`是枚举类型,`RED`, `...
java枚举结果类、根据状态值获取枚举值 Controller: /** 模块类型枚举 */ model.addAttribute("mType", ModuleTypeEnum.ModuleTypeShow()); ftl: value="${mType.key}:${mType.value}” </#list>
- **自动实现接口**:枚举类型会自动实现`java.lang.Enum<E>`接口,其中`E`是枚举类型的名称。 - **安全性**:枚举类型的成员是固定的,不允许外部添加或修改成员。 - **单例模式**:每个枚举成员都是单例的,只能被...
- 虽然Java枚举不能直接继承其他枚举或类,但它们隐式地扩展了`java.lang.Enum`类,因此可以实现接口。 7. **枚举与switch语句**: - 枚举常量可以用于`switch`语句,这是枚举类型的一个重要应用场景: ```java ...
Java 枚举类型在 switch 语句正确使用方法详解 Java 枚举类型是 Java 语言中的一种特殊类型,用于定义一组具有一些公共特征的常量。Java 枚举类型在 switch 语句中的正确使用方法是本文的主要内容。通过示例代码,...