`
足至迹留
  • 浏览: 495708 次
  • 性别: Icon_minigender_1
  • 来自: OnePiece
社区版块
存档分类
最新评论

枚举原理及使用

阅读更多
参考:《java入门经典》《java核心技术 卷1》网络
1.枚举引入
  通常需要一些只能从预定义的固定集合中取值的变量。例如,假设想要定义一个名为weekday的整型变量,用来存储表示星期几的整数值。该变量最好能限制在7个可能的值之内,每个值逐个对应星期一到星期日。这种情形下一种称作枚举类型(enumerated type),甚至简单地称作枚举(enumeration)的工具是自然的选择。可以使用如下声明语句为这种情况定义一个枚举:
enum Day {Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday }

这里定义了一个新的类型Day,变量只能存储在括号中设定的其中一个值。名称Monday、
Tuesday 一直到Sunday 都称为枚举常量,而且它们标识了Day 类型的变量中仅允许的值。事实上,这些名称会对应到整数值,默认情况下从0 开始,但是它们与整型变量不同,因为它们只在枚举Day的上下文中存在。

注意:在Day 枚举定义的最后没有分号(如果枚举中还定义了其他成员,则必须有分号)。因为这里是定义一个类型,所以在反括号的后面不需要
添加分号。类型名Day 的开头使用一个大写的D,因为按照约定,定义的类型都以大写字母开头。
枚举常量的名称通常用全大写命名,对应了普通public final static常量的规则。

有了这个新类型,现在可以按照如下方式定义变量weekday:
Day weekday = Day.Tuesday;
这里声明了Day 类型的变量weekday 并且将其初始化为Tuesday。注意提供weekday 初始值的
枚举常量必须用枚举类型名限定(switch语句中的case后面使用枚举常量时不需要用枚举类型限定)。如果不要限定名,编译器就无法认出该常量。

枚举通常能包含所需要数目的枚举常量。这里是一个表示每年月份的枚举类型:
enum Month { January, February, March , April , May , June,
July , August , September, October, November, December }

可以按如下方式定义这种类型的变量:
Month current = Month.September; // Initialize to September
如果之后想要修改变量中存储的值,可以将其设置为一个不同的枚举常量:
current = Month.October;
current 变量现在包含枚举常量值October。

2.枚举使用
枚举类型其实是一种特殊形式的类,声明enum时不能继承一个超类,默认所有的枚举都自动地继承java.lang.Enum。在代码中定义枚举类型时,设定的枚举常量以一个类的实例被创建,这个类以java.lang包中的Enum类作为超类,所以跟类一样,在类的定义中可以放置枚举类型的定义,也可以将枚举类型定义放在一个单独的源文件中。

每个枚举常量对应的对象将常量的名称存储在一个域中,而枚举类类型从Enum类中继承toString()方法。Enum类中的toString()方法返回 枚举常量的原始名称,所以使用println()方法输出枚举常量时会获得枚举常量的名称。

表示枚举常量的对象也存储一个整数域。默认地,枚举中的每个常量都被赋予一个与其他常量不同的整数值。这些值按照设定它们时的顺序被赋给枚举常量,第一个常量从0开始,然后第二个常量是1,后面依此类推。通过调用常量的ordinal()方法就能获得它的整数值,但是一般来说不应该需要这样做。

可以使用equals()方法来比较枚举类型的整数值是否相等(但是,永远不要使用equals,直接使用==比较,因为我们定义了枚举类型就不希望再创建新常量对象了,直接使用已经定义好的实例)。例如,假设已经定义了枚举类型Season,其中包括了枚举常量spring、summer、fall和winter,可以编写如下内容:
   Season now = Season.winter;
   if(now.equals(Season.winter))
   {
       System.out.println("It is definitely winter!");
   }

这个枚举类类型的equals()方法从Enum类继承而来,另外还继承了基于枚举类型实例的整数值进行比较的compareTo()方法。如果方 法调用的实例的整数值小于作为参数传入的实例,结果为负整数;如果它们相等,结果为0;如果当前实例的整数值大于作为参数传入的值,结果为正整数。因此, 当定义这些枚举常量时,它们的设定顺序决定了compareTo()方法实现的顺序。可以这样使用:
if(now.compareTo(Season.summer) > 0)
    System.out.println("It is definitely getting colder!");

枚举引入的values()方法是一个属于枚举类类型的静态方法,该方法返回一个包括在基于集合的for循环中使用的所有枚举常量的集合对象。

2.1 添加成员到枚举类

因为枚举是类,所以在定义枚举类型时可以添加自己的方法和域,还可以添加属于自己的构造函数来初始化任何引入的额外域。下面看一个例子。假设想要为衣服(比如夹克)的尺寸定义一个枚举类型,初始的定义可能如下:
public enum JacketSize { small, medium, large, extra_large, extra_extra_large }
然后会发现,可能想要记录应用到每个夹克尺寸的平均胸围。可以将上面的枚举定义修改为如
下形式:
public enum JacketSize {
small(36), medium(40), large(42), extra_large(46), extra_extra_large(48);
// Constructor
JacketSize(int chestSize) {
this.chestSize = chestSize;
}
// Method to return the chest size for the current jacket size
public int chestSize() {
return chestSize;
}
private int chestSize; // Field to record chest size
}


注意这里的枚举常量列表以分号结束。列表中的每个常量在括号中都有对应的胸围,而且这些值会被传递给添加到类中的构造函数。在之前的JacketSize 定义中每个枚举常量的出现都会导致对枚举类默认构造函数的一次调用
事实上,可以在每个常量名称的后面放一对空括号,这样仍然会编译。但是,这不会增加代码的清晰度。因为已经定义了一个构造函数,所以不会为枚举类型定义默认的构造函数。因此,不能只使用名称来编写枚举常量,必须在每个枚举常量的后面添加一对括号并在其中包括一个值作为胸围。当然,如果想要在枚举中选择省略一些常量的胸围尺寸,也可以定义自己的默认构造函数并且为chestSize 赋一个默认值。

即使已经添加了自己的构造函数,从基类Enum 中继承的用来存储常量名称及其整数值的域仍
然会被正确地设置。compareTo()方法实现的常量顺序仍然由定义中常量出现的顺序决定。注意决不能将枚举类中的构造函数声明为public。如果这样做,enum 类定义就不会被编译。唯一允许对定义为枚举的类的构造函数应用的修饰符是private,这导致只能在类的内部调用构造函数。

2.2 根据枚举值获取枚举类
   
public enum Day
    {
    	A(1),B(2),C(5);
    	private int value;

    	Day(int value)
    	{
    	    this.value = value;
    	}
    	
    	public int getValue()
    	{
    	    return value;
    	}
    	
    	public static Day getEnumByValue(int value)
    	{
    		Day[] day = Day.values();
    		
    		for (Day d : day)
    		{
    			if (d.getValue() == value)
    			{
    				return d;
    			}
    		}
    		
    		return null;
    	}
    	
    }

这里用到了枚举的静态方法values()返回所有的枚举常量,还可以使用Day.class.getEnumConstants()实现同样的功能。

3. 枚举原理
枚举类型经过编译器编译之后产生的是一个final class文件,该类继承了java.lang.Enum<E>。所以定义自己的枚举类型时不能再extends其他父类。而每个枚举常量都被编译成枚举类的public static final **Enum类型的常量。
比如:
public enum MessageTypeEnum {
    Order_New(1, "OrderPipe_ghost", 1, "abc");
    private Integer index;
    private String topic;
    private Integer messageType;
    private String description;
    private static ConcurrentHashMap<String, Integer> messageTypeMap = null;

    static {
        messageTypeMap = new ConcurrentHashMap<String, Integer>();
        for (MessageTypeEnum o: MessageTypeEnum.values()){
            messageTypeMap.put(o.getTopic(),o.getMessageType());
        }
    }

    public static Map<String, Integer> getMessageTypeMap(){
        return messageTypeMap;
    }

    private MessageTypeEnum(Integer index, String topic, Integer messageType, String description) {
        this.index = index;
        this.topic = topic;
        this.messageType = messageType;
        this.description = description;
    }
...
}

利用javap -s class文件可以看到:
ervice\render\MessageTypeEnum
Compiled from "MessageTypeEnum.java"
public final class com.an.service.render.MessageTypeEnum extends java.lan
.Enum{
public static final com.an.service.render.MessageTypeEnum Order_New;
  Signature: Lcom/an/libra/service/render/MessageTypeEnum;
public static com.an.service.render.MessageTypeEnum[] values();
  Signature: ()[Lcom/an/libra/service/render/MessageTypeEnum;
public static com.an.service.render.MessageTypeEnum valueOf(java.lang.Str
ng);
  Signature: (Ljava/lang/String;)Lcom/an/libra/service/render/MessageTypeEnum;
public static java.util.Map getMessageTypeMap();
  Signature: ()Ljava/util/Map;
public java.lang.Integer getIndex();
  Signature: ()Ljava/lang/Integer;
public void setIndex(java.lang.Integer);
  Signature: (Ljava/lang/Integer;)V
public java.lang.String getTopic();
  Signature: ()Ljava/lang/String;
public void setTopic(java.lang.String);
  Signature: (Ljava/lang/String;)V
public java.lang.Integer getMessageType();
  Signature: ()Ljava/lang/Integer;
public void setMessageType(java.lang.Integer);
  Signature: (Ljava/lang/Integer;)V
public java.lang.String getDescription();
  Signature: ()Ljava/lang/String;
public void setDescription(java.lang.String);
  Signature: (Ljava/lang/String;)V
static {};
  Signature: ()V
}

注意其中的:
public final class com.an.service.render.MessageTypeEnum extends java.lan.Enum
public static final com.an.service.render.MessageTypeEnum Order_New;


4.枚举示例
http://www.iteye.com/topic/1116193
http://www.cnblogs.com/linjiqin/archive/2011/02/11/1951632.html
http://socket.blog.163.com/blog/static/209873004201061440047/

枚举通常替代常量定义有固定范围的常量。经常会用在switch语句中。
查看enum的字节码可以看到,每个枚举常量被编译为枚举类的静态常量。
参考:http://www.cnblogs.com/frankliiu-java/archive/2010/12/07/1898721.html

5.枚举序列化部分讨论
http://www.iteye.com/topic/1052055
http://wenku.baidu.com/link?url=qQBwVRubjTG6QsiqBszi7wyfVrZE9m2oLEpLpOgR9en-k9YIvrfR_Nx3MlYIG3Bs8YCp3JtnXwpQ4as_1o6juhHd0xCvcHTLD3F0hHQI_E_

6.枚举异常IllegalArgumentException
jdk1.6源码:
public static <T extends Enum<T>> T valueOf(Class<T> enumType,
                                                String name) {
        T result = enumType.enumConstantDirectory().get(name);
        if (result != null)
            return result;
        if (name == null)
            throw new NullPointerException("Name is null");
        throw new IllegalArgumentException(
            "No enum const " + enumType +"." + name);
    }

当调用valueOf,且name不是定义的枚举常量(注意是枚举常量,不是ordinal也不是括号内指定的别名)时会抛出IllegalArgumentException异常,且会打出日志:"No enum const " + enumType +"." + name

还可以参见:
http://stackoverflow.com/questions/12639791/what-is-the-reason-for-java-lang-illegalargumentexception-no-enum-const-class-e
分享到:
评论

相关推荐

    Java面试枚举从使用到原理

    本篇文章将深入探讨Java枚举的使用及其背后的原理。 一、枚举的定义与使用 1. 基本用法: 在Java中,枚举可以通过`enum`关键字来创建。例如,我们可以定义一个表示一周七天的枚举类型: ```java public enum ...

    枚举类型.pptx

    #### 六、枚举的底层原理 在Java中,枚举类型本质上是一个`final`类,自动继承`Enum`类,并且每个枚举常量都是该类的一个实例。编译器还会自动为枚举类型添加一些默认的方法,如`values()`和`valueOf()`等。 #### ...

    枚举硬件

    这个过程对于操作系统来说至关重要,因为只有正确地枚举硬件,才能确保系统能正确地驱动和使用这些设备。下面将详细介绍枚举硬件的相关知识点。 1. **硬件识别**:当计算机启动时,BIOS(基本输入输出系统)会进行...

    使用类常量方式实现PHP枚举

    本篇文章将深入探讨如何使用类常量来实现PHP枚举以及其背后的原理和应用场景。 ### 1. 类常量介绍 类常量是类的一部分,它们是静态的,不能被改变,且在类的整个生命周期内保持不变。声明类常量使用`const`关键字...

    枚举系统进程api的使用

    在Windows操作系统中,枚举系统进程是...以上内容涵盖了标题和描述中提到的“枚举系统进程API的使用”,详细解释了如何使用这些API以及它们的工作原理。希望这个详尽的介绍对你在学习和使用枚举系统进程API时有所帮助。

    mfc 枚举进程 mfc 枚举进程

    一、MFC 枚举进程的基本原理 在Windows操作系统中,枚举进程主要涉及到以下几个关键的Windows API 函数: 1. `EnumProcesses`:这是一个系统级别的API函数,用于获取当前系统中所有活动进程的进程ID列表。它接受一...

    USB详细枚举过程(经测试正确)

    在提供的代码片段中,可以看到使用Windows API进行USB设备枚举的例子。`SetupDiGetClassDevs`函数用于获取所有符合指定类(这里是HID类)的设备信息。`HidD_GetHidGuid`获取HID设备的全局唯一标识符(GUID),`...

    枚举USB设备CODE

    2. **C++**:在Windows上,可以使用Windows API函数如`SetupDiGetClassDevs()`来获取设备信息,然后使用`SetupDiEnumDeviceInterfaces()`枚举特定类型的USB设备。在Linux中,可以使用libusb库,通过`libusb_get_...

    C#中的枚举类型:定义、使用与最佳实践

    本文将详细介绍如何在C#中定义和使用枚举类型,以及相关的一些最佳实践。 枚举类型是C#中一种强大且灵活的特性,它们提供了一种类型安全的方式来表示一组相关的常量。通过合理地定义和使用枚举,可以提高代码的...

    自己整理的目录枚举工具

    对于IT从业者来说,了解目录枚举原理并能编写或使用相关的工具,是提升工作效率的重要技能。通过实践,你可以深入理解文件系统的工作方式,同时也能更好地应对各种实际工作中的挑战。 8. **注意事项**: 在使用...

    文件枚举工具

    在IT行业中,文件枚举是一项基础但至...无论你是系统管理员、开发者还是数据科学家,掌握这种工具的使用和原理,都能极大地提高工作效率。通过深入学习相关API和编程技巧,你将能够创建更复杂、更强大的文件管理系统。

    串口枚举,查询串口各种信息

    本文将详细讲解串口枚举及查询串口信息的相关知识点,结合提供的文件名,我们可以推测这是一个用于枚举和查询系统串口信息的小型应用程序。 首先,"串口枚举"是指在计算机中获取所有可用的串行端口的过程。在...

    易语言枚举内核驱动

    本文将深入探讨“易语言枚举内核驱动”这一主题,结合源码分析枚举内核驱动的基本原理,以及如何利用相关函数进行文件名获取、内存操作等关键步骤。 首先,我们要理解什么是内核驱动。在Windows操作系统中,内核...

    VC枚举系统所有窗口

    这个函数的工作原理和`EnumWindows`类似,只是它只枚举一个特定窗口的子窗口。 在实际应用中,枚举窗口可能涉及到更复杂的逻辑,例如根据窗口类名或特定属性筛选窗口,或者在枚举过程中对窗口进行某些操作。了解...

    WPF枚举绑定

    本篇文章将深入探讨WPF中的枚举绑定,包括其原理、实现方式以及应用场景。 1. 枚举类型简介 枚举是C#中的一种数据类型,用于定义一组命名的常量。这些常量通常代表特定的值,例如状态、方向或颜色。在WPF中,枚举...

    易语言枚举内核对象句柄

    在计算机编程领域,尤其是涉及到操作系统级别的操作时,"内核对象句柄"是一个重要的...这需要深入理解操作系统的工作原理以及易语言的编程模型。正确使用这个功能,可以帮助我们开发出更加高效和强大的系统级应用程序。

    易语言源码易语言枚举窗口进程.rar

    在"易语言源码易语言枚举窗口进程.rar"这个压缩包中,包含了两个关键文件:"枚举窗口进程.e"和"源码使用说明.txt",它们提供了关于易语言如何枚举窗口进程及其相关知识点的实践示例和指导。 枚举窗口进程是Windows...

    易语言枚举MTP设备

    它不仅可以帮助你掌握设备枚举和MTP通信的基本原理,还能让你了解如何在易语言环境下进行系统级别的编程。同时,这也为其他类型的设备枚举和管理提供了一个可参考的模板。通过深入分析和实践,你将能够扩展这些知识...

    枚举窗口的源代码资源

    下面我们将详细探讨枚举窗口的原理和实现方法。 首先,我们需要了解几个关键的Windows API函数: 1. **EnumWindows**: 这是用于枚举所有顶层窗口的主要函数。它接受一个回调函数指针和一个用户自定义的数据指针...

    枚举算法及其程序实现

    在教学过程中,教师引导学生通过小组合作,用流程图描绘出解决问题的步骤,进一步理解枚举算法的工作原理。 教学难点包括掌握解题思路、绘制流程图和程序实现。在绘制流程图时,学生需要理解开始、结束、判断、循环...

Global site tag (gtag.js) - Google Analytics