`
whitesock
  • 浏览: 484624 次
  • 性别: Icon_minigender_1
  • 来自: 大连
社区版块
存档分类
最新评论

Inside java.lang.Enum

    博客分类:
  • SE
阅读更多

1 Introduction to enum
    Java SE 5中引入了枚举,同时添加了一个新关键字enum。下面是个枚举的例子:

public enum Suit {
	CLUBS, DIAMONDS, HEARTS, SPADES;
}

    枚举类型也是普通的Java类,继承自java.lang.Enum并默认实现了java.lang.Comparable接口和java.io.Serializable接口。所有的枚举类型都是final类,枚举值都是public static final,由于枚举值是常量,因此枚举值的名称通常应该大写。
     枚举类型也可以声明构造函数(只能是私有或者包级私有)、成员变量和成员方法,此外也能实现接口。需要注意的是,成员变量和成员方法的声明必须放在所有枚举值定义的后面,例如:

public enum Status {
	//
	Normal("normal"), Warning("warning"), Error("error"), Fatal("fatal");
	
	//
	private String description;
	
	private Status(String description) {
		this.description = description;
	}
	
	public String getDescription() {
		return description;
	}

	public void setDescription(String description) {
		this.description = description;
	}
}

    Enum声明了name()方法和oridinal()方法,分别用于返回枚举值的名称和该枚举值在枚举类型中声明的顺序(从0开始),例如NORMAL.ordinal()返回0。Enum改写了toString方法,返回枚举值的名称。下面是个简单的例子:

public static void main(String args[]) {
	//
	System.out.println("super class: " + Status.class.getSuperclass());
	
	//
	System.out.println(Status.valueOf("Normal").getDescription());
	
	//
	for(Status s: Status.values()) {
		System.out.println(s + ":" + s.ordinal());
	}
	
	//
	Status status = Status.Normal;
	switch(status) {
	case Normal:
		System.out.println("Status.Normal");
		break;
	case Warning:
		System.out.println("Status.Warning");
		break;
	case Error:
		System.out.println("Status.Error");
		break;
	case Fatal:
		System.out.println("Status.Fatal");
		break;
	default:
		System.out.println("unknown");
	    break;
	}
	
	//
	EnumMap<Status, String> map = new EnumMap<Status, String>(Status.class);
	map.put(Status.Normal, "normal status");
	map.put(Status.Warning, "warning status");
	map.put(Status.Error, "error status");
	map.put(Status.Fatal, "fatal status");
	
	//
	EnumSet<Status> set = EnumSet.of(Status.Normal, Status.Warning);
	for(Status s : set) {
		System.out.println(s);
	}
}

    以上程序的输出如下。需要注意的是,case语句只需将其写成 case Normal 即可,也就是说不必写成 case Status.Normal,实际上如果写成Status.Normal,那么会导致编译错误。

super class: class java.lang.Enum
normal
Normal:0
Warning:1
Error:2
Fatal:3
Status.Normal
Normal
Warning

 

 

2 Inside java.lang.Enum
2.1 Instantiation

    首先java.lang.Enum类的签名如下,其中<E extends Enum<E>>是递归类型限制,主要目的是提供compareTo(E e) 而不是compareTo(Enum e)。

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

 

    java.lang.Enum中唯一的构造函数如下,所有的成员变量都在构造函数内初始化。由于所有的成员变量都是不可变类型或者基本类型,因此没有额外的保护性拷贝。构造之后,所有的成员变量便处于只读状态。需要注意的是,java.lang.Enum的子类不一定是不可变类(虽然通常应该是不可变类),因为程序中定义的枚举类型可以包含可变的成员变量。

protected Enum(String name, int ordinal) {
    this.name = name;
    this.ordinal = ordinal;
}

 

    java.lang.Enum类提供了一个静态工具方法,用于获得某个枚举类型中,名为name的枚举值。该方法通过调用java.lang.Class的 enumConstantDirectory()方法获得该枚举类型所有枚举值的map。java.lang.Class的enumConstantDirectory()方法内又通过反射调用了该枚举类型的values()方法获得所有的枚举值。需要注意的是,java.lang.Enum中并没有一个名为values()的静态方法,这个方法是编译器在编译枚举类型时添加的。

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);
}
 

2.2 Equality

public final boolean equals(Object other) { 
    return this==other;
}

public final int hashCode() {
    return super.hashCode();
}

    从以上代码中可以看出,对于枚举值的相等性判断,只需要判断引用是否相等即可。需要注意的是,这是在充分考虑了反射、对象克隆和序列化等诸多因素之后作出的决定。

    java.lang.reflect.Constructor的newInstance()方法中有如下代码,禁止了通过反射构造枚举对象:

if ((clazz.getModifiers() & Modifier.ENUM) != 0) 
    throw new IllegalArgumentException("Cannot reflectively create enum objects");
 

2.3 Comparison
    以下是跟枚举比较相关的代码:

public final Class<E> getDeclaringClass() {
    Class clazz = getClass();
    Class zuper = clazz.getSuperclass();
    return (zuper == Enum.class) ? clazz : zuper;
}

public final int compareTo(E o) {
    Enum other = (Enum)o;
    Enum self = this;
    if (self.getClass() != other.getClass() && // optimization
            self.getDeclaringClass() != other.getDeclaringClass())
        throw new ClassCastException();
    return self.ordinal - other.ordinal;
}

    假设程序中定义的所有枚举类型都是继承自java.lang.Enum,而且所有的枚举类型都被声明为final类,这是否意味着所有枚举值的super class都应该是java.lang.Enum?为什么在getDeclaringClass()方法内会有对super class的判断呢?分析以下例子:

public enum Operation {
    PLUS { double eval(double x, double y) { return x + y; } },
    MINUS { double eval(double x, double y) { return x - y; } },
    TIMES { double eval(double x, double y) { return x * y; } },
    DIVIDE { double eval(double x, double y) { return x / y; } };

    abstract double eval(double x, double y);
    
    public static void main(String args[]) {
        System.out.println(Operation.TIMES.getClass());
        System.out.println(Operation.TIMES.getClass().getSuperclass());
        System.out.println(Operation.TIMES.getDeclaringClass());
    }
}

    以上程序的输出如下:

class Operation$3
class Operation
class Operation

    从这个例子可以看出,并不是所有的枚举值的super class都是Emum.class。在compareTo()方法内需要判断getDeclaringClass()和ordinal是否相等。就像其注释中说明的那样,判断getClass()是否相等只是一种优化。

 

    此外,java.lang.Class类中包含以下代码,用于判断一个类是否是枚举类型。需要注意的是,这里没有使用getDeclaringClass(),而是直接使用getSuperclass()进行判断。

public boolean isEnum() {
    // An enum must both directly extend java.lang.Enum and have
    // the ENUM bit set; classes for specialized enum constants
    // don't do the former.
    return (this.getModifiers() & ENUM) != 0 && 
    this.getSuperclass() == java.lang.Enum.class;
}

 

2.4 Clone
    以下是java.lang.Enum类的clone()方法,该方法中直接抛出CloneNotSupportedException异常,这保证了java.lang.Enum无法被克隆,从而保证了枚举值的单例性(通常情况下,只有一个继承链上的除了java.lang.Object之外的所有类都在clone()方法内返回通过调用super.clone()方法返回的对象,那么才能保证clone的正确性)。

protected final Object clone() throws CloneNotSupportedException {
        throw new CloneNotSupportedException();
}

 

2.5 Serialization
    java.lang.Enum类中序列化相关的代码如下:

private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
    throw new InvalidObjectException("can't deserialize enum");
}

private void readObjectNoData() throws ObjectStreamException {
    throw new InvalidObjectException("can't deserialize enum");
}

    java.lang.Enum类实现了Serializable接口,但是却在readObject()和readObjectNoData()方法内直接抛出异常(如果某个类因为继承的原因实现了Serializable接口,而该类却不希望被序列化/反序列化,那么通常可以考虑在readObject()和writeObject()方法中直接抛出异常)。
    实际上,Java的序列化机制对于枚举类型有特殊的处理,即没有使用普通对象的序列化形式:尽管java.lang.Enum中的name和ordial成员变量都没有声明为transient,实际上序列化过程中写入流的只有name;反序列化过程中通过调用Enum.valueOf(Class<T> enumType, String name)静态方法构造枚举值,从而保证了枚举值的单例性。

9
0
分享到:
评论
2 楼 ouchxp 2010-12-22  
axis1.4里面有个包名叫enum
升级到JDK1.5后.和enum关键字产生冲突.代码大面积红叉....
1 楼 fujohnwang 2010-08-06  
      enumClass.get("XXX").get(null);

相关推荐

    org.apache.commons.lang jar包下载(commons-lang3-3.1.jar)

    org.apache.commons.lang.enum.Enum.class org.apache.commons.lang.enum.EnumUtils.class org.apache.commons.lang.enum.ValuedEnum.class org.apache.commons.lang.enums.Enum$Entry.class org.apache.commons...

    org.apache.commons.lang jar包下载

    org.apache.commons.lang.enum.Enum.class org.apache.commons.lang.enum.EnumUtils.class org.apache.commons.lang.enum.ValuedEnum.class org.apache.commons.lang.enums.Enum$Entry.class org.apache.commons...

    java.lang.NullPointerException出现的几种原因及解决方案

    在比较字符串与文字时,如果文字可以是一个字符串或Enum的元素,也可能会抛出java.lang.NullPointerException异常。例如: String str = null; if (str.equals("Test")) { // 这里将抛出java.lang....

    JBuider第六章:Java.lang包.rar

    Java 5引入的枚举类型(如`java.lang.enum`)提供了一种安全的常量表示方式。 7. **System.in/err/out**:`System`类的静态变量`in`、`err`和`out`分别代表标准输入、错误输出和标准输出流,它们在I/O编程中扮演着...

    commons-lang.jar

    org.apache.commons.lang.enum.Enum.class org.apache.commons.lang.enum.EnumUtils.class org.apache.commons.lang.enum.ValuedEnum.class org.apache.commons.lang.enums.Enum$Entry.class org.apache.commons....

    spring boot 枚举使用的坑整理

    在 Java 中,枚举类型可以使用 enum 关键字来定义。 在 Spring Boot 应用程序中,枚举类型经常被用于定义一些固定的值,例如订单状态、用户角色等。然而,在使用枚举类型时,需要注意一些坑,否则可能会出现一些...

    mysql与oracle数据类型对应关系.docx

    - `BIGINT`: 用来存储大整数,对应 Oracle 的 `NUMBER(19,0)`,Java 中可使用 `java.lang.Long` 对应。 - `BIT`: 存储位数据,Oracle 没有直接对应的数据类型,通常使用 `RAW` 类似。 - `BLOB`: 用于存储大对象,...

    java官方中文API

    7. **枚举和注解**:Java 5引入了枚举和注解,API文档中也有详细的描述,例如`java.lang.Enum`是所有枚举类型的基类,`java.lang.annotation`包提供了注解的相关类。 8. **多线程**:Java提供了丰富的多线程支持,`...

    JAVA中文API文档

    12. **枚举(Enum)**: `java.lang.Enum`提供了枚举类型的支持,枚举常量可以拥有方法和属性,使得常量集合更易于管理。 通过深入学习这份中文API文档,你可以全面掌握Java平台的核心功能,无论你是初学者还是有...

    JAVA-API.zip_java api

    "JAVA-API.zip"的压缩包可能还包含了其他高级特性的文档,如反射(java.lang.reflect)、注解(java.lang.annotation)、泛型(generics)、枚举(enum)以及Lambda表达式等。这些内容是Java 5及以后版本引入的,极...

    JavaAPI(官方英文版)

    4. **枚举(Enum)**:Java允许定义枚举类型,这是一种特殊的类,可以有预定义的实例。比如`java.util.concurrent.TimeUnit`枚举用于表示时间单位。 5. **异常(Exception)**:Java通过异常处理来处理程序运行时...

    commons-lang3-3.1 API

    其中的lang.enum已不建议使用,替代它的是紧随其后的lang.enums包。 lang包主要是一些可以高度重用的Util类;lang.builder包包含了一组用于产生每个Java类中都常使用到的toString()、 hashCode()、equals()、...

    JAVA API官方文档中文版

    5. **枚举和注解**:Java 5引入了枚举和注解,这些在API文档中也有详尽的解释,如`java.lang.annotation`包下的注解类型,以及`java.lang.Enum`作为所有枚举类型的基类。 6. **附录**:通常包括一些补充信息,如...

    java.util包总结

    11. EnumSet和EnumMap:针对枚举类型(enum)的高效集合实现,优化了枚举操作。 12. WeakHashMap:键使用弱引用的Map,当键不再被引用时,条目会自动从Map中移除。 13. Timer和TimerTask:定时任务调度,可以安排...

    java-api的html版

    8. **枚举和注解**:Java 5引入了枚举和注解,API文档也对这些新特性进行了详细解释,如`java.lang.Enum`作为所有枚举类型的基类,`java.lang.annotation`包下的注解接口。 9. **并发编程支持**:Java API提供了...

    API.rar_Chinese jav_Javaapi _chinesejav_jav chinese_javaAPI中文文档

    10. **枚举(Enum)**:Java 5引入的枚举类型是常量的集合,可以避免使用传统的整数常量来表示一组固定的值,增强了代码的可读性和安全性。 学习和理解Java API中文文档对于Java开发者至关重要,它不仅提供了对API...

    [图文]Java标准类库-.doc

    1. **基础包**:`java.lang`是最基础的包,包括了所有Java程序都会自动导入的基本类,如`Object`(所有类的父类)、`String`(字符串类)、`System`(系统相关操作)以及异常处理类`Exception`等。 2. **集合框架**...

    javaenum(枚举)使用详解+总结.pdf

    枚举在Java中被设计为一种特殊的类,它们默认继承自`java.lang.Enum`抽象类,并且是单继承的,这意味着它们无法再继承其他类,但可以实现多个接口。下面我们将深入探讨enum的使用方法、特性以及常见的操作。 1. **...

    Java枚举类型Enum的用法

    枚举默认继承`java.lang.Enum`类,因此它们不能直接继承其他类,但可以实现接口。这使得枚举可以具有特定的行为。 6. **枚举常量的遍历** 可以通过for-each循环遍历枚举的所有实例,如: ```java for (Color ...

    JAVA帮助文档(CHM格式,下载就能看,不用安装其他阅读软件)

    5. **枚举和注解**:Java 5引入了枚举和注解,这些在API文档中也有详细介绍,例如`java.lang.Enum`表示枚举类型,`java.lang.annotation.Annotation`是注解的基类。 6. **异常处理**:Java API文档也涵盖了所有的...

Global site tag (gtag.js) - Google Analytics