`
喻红叶
  • 浏览: 40819 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

Java枚举类型

 
阅读更多

关键字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枚举类型(Enum)是Java SE 5.0引入的一种新的数据类型,它为开发者提供了更为强大且安全的方式来表示一组常量。枚举在Java中不仅是一个类,还是一种特殊的类型,允许我们定义自己的常量集合。接下来,我们将...

    理解java枚举类型

    Java枚举类型是Java语言中的一种特殊的类,用于定义一组固定的常量集合。它在Java中扮演着重要的角色,提供了一种安全、类型化的常量表示方式,比传统的final static变量更具有优势。理解Java枚举类型对于编写高质量...

    Java枚举类型.pdf

    总结起来,Java枚举类型是一个强大的工具,它可以替代`static final`常量来表示一组固定的值,提供类型安全、易于维护的代码。通过枚举,我们可以更方便地管理常量,减少错误,并增加代码的灵活性。枚举是Java中一个...

    简单总结java枚举类型

    Java枚举类型是Java语言中一种特殊的类,用于定义固定的常量集合,它提供了一种安全、类型化的方式来表示一组有限的值。枚举在Java中被引入为一个完整的类型,不同于C++中的枚举,这使得Java枚举更加强大且易于使用...

    java枚举类型说明

    ### Java枚举类型详解 #### 一、引言 在Java编程语言中,枚举(Enum)作为一种重要的数据类型,在程序设计中扮演着不可或缺的角色。本文将深入探讨Java枚举类型的特性和用法,并通过具体实例说明其优势所在。枚举...

    JAVA枚举类型的用法详解

    下面我们将深入探讨Java枚举类型的常见用法。 首先,枚举类型在本质上等同于定义了一组静态常量。创建枚举类型的语法如下: ```java public enum Belle { para1, para2, para3, para4; } ``` 这会创建一个名为`...

    全面掌握java枚举类型(enum-type)1

    全面掌握 Java 枚举类型(enum type) Java 枚举类型是一种特殊的数据类型,它可以取有限个数的明确值。枚举类型的引入解决了 int 枚举模式和 String 枚举模式的缺点,提供了类型安全性、可读性和性能等优势。 ...

    如何使用Java枚举类型

    一个关于JAVA枚举类型的MHT文件,包含JAVA枚举类型的用法,以及JDK版本的问题。

    Java 枚举类型案例.zip

    在本压缩包中,"Java 枚举类型案例"可能包含了多个示例,以帮助我们深入理解Java枚举类型的使用。 1. **枚举的定义** 在Java中,枚举是通过关键字`enum`来定义的。例如,创建一个表示星期的枚举类型: ```java ...

    java枚举类型enum的使用

    ### Java 枚举类型 enum 的使用详解 #### 一、枚举类型概述 在 Java 中,枚举(enum)是一种特殊的类,它被用来表示一组固定的常量值。枚举类型自 JDK 1.5 开始引入,为开发者提供了一种更加安全、简洁的方式来...

    2021年JAVA枚举类型知识点.docx

    以下是关于Java枚举类型的详细知识点: 1. **枚举定义**: - 枚举类型通过`enum`关键字来定义,例如`public enum Color {RED, BLUE, BLACK, YELLOW, GREEN}`。 - 枚举实际上是`java.lang.Enum`类的子类,这意味着...

    JAVA枚举类型[归纳].pdf

    JAVA枚举类型[归纳].pdf

    高阶Java-Java枚举类型 enum 应用详解

    本篇文章将深入探讨Java枚举的特性、用法以及如何在实际开发中充分利用它们。 一、枚举的基本用法 1. 声明枚举类型: ```java public enum Color { RED, GREEN, BLUE } ``` 在这里,`Color`是枚举类型,`RED`, `...

    java枚举结果类、根据状态值获取枚举值

    java枚举结果类、根据状态值获取枚举值 Controller: /** 模块类型枚举 */ model.addAttribute("mType", ModuleTypeEnum.ModuleTypeShow()); ftl: value="${mType.key}:${mType.value}” &lt;/#list&gt;

    java枚举类型优秀源代码

    - **自动实现接口**:枚举类型会自动实现`java.lang.Enum&lt;E&gt;`接口,其中`E`是枚举类型的名称。 - **安全性**:枚举类型的成员是固定的,不允许外部添加或修改成员。 - **单例模式**:每个枚举成员都是单例的,只能被...

    JAVA枚举类型的用法.doc

    - 虽然Java枚举不能直接继承其他枚举或类,但它们隐式地扩展了`java.lang.Enum`类,因此可以实现接口。 7. **枚举与switch语句**: - 枚举常量可以用于`switch`语句,这是枚举类型的一个重要应用场景: ```java ...

    Java枚举类型在switch语句正确使用方法详解

    Java 枚举类型在 switch 语句正确使用方法详解 Java 枚举类型是 Java 语言中的一种特殊类型,用于定义一组具有一些公共特征的常量。Java 枚举类型在 switch 语句中的正确使用方法是本文的主要内容。通过示例代码,...

Global site tag (gtag.js) - Google Analytics