`
whitesock
  • 浏览: 478551 次
  • 性别: 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...

    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基础知识点总结.docx

    &lt; java.lang &gt;StringBuilder字符串缓冲区:★★★☆ 74 基本数据类型对象包装类★★★☆ 75 集合框架:★★★★★,用于存储数据的容器。 76 &lt; java.util &gt; Collection接口 77 &lt; java.util &gt;Iterator接口 78 &lt; java....

    commons-lang3-3.1 API

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

    Demo4Enum.java

    Demo4Enum.java

    Java 高级特性.doc

    import java.lang.Integer.parseInt; public class StaticImport { int x = parseInt("123"); System.out.println(x); } 这样的程序如果不在IDE 工具中输入,是很难看出这个程序代码会出现问题,可它偏偏就出问题...

    Java__enum.mp4

    Java__enum.mp4

    Enum汇总大全详细讲解

    Enum.doc Enum.docEnum.doc Enum.doc Enum.doc Enum.doc Enum.doc Enum.doc Enum.doc

    javaenum学习.pdf

    javaenum学习.pdf

    Java SE程序 Enum枚举类

    Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类Java SE程序 Enum枚举类...

    JavaLanguage

    The Java Language Specification 3rd

    Filter_Enum.rar_enum.filter

    用于枚举DShow过滤器,并且获取各个过滤器的详细信息;不同于标准教程介绍的方法,这个软件包采用【直接解析】方法,能够获取最全面的类型细节信息;

    java enum 枚举 学习资料

    java enum详细教程。由浅入深,包括基本语法方面..很适合新手学习。/n各位看官。绝对超值。

    Java对象序列化和反序列化工具Xson.zip

    7.Enum 8.TimeZone 9.Class 10.BigDecimal 11.BigInteger 12.Class 13.StringBuffer 14.StringBuilder 15.URI 16.URL 17.UUID 18.Locale 19.Currency 20.TimeZone 21.java.util.Date 22.java.sql....

    java enum 枚举的spring boot2.x完美实现demo源码

    ava enum 枚举的spring boot2.x完美实现demo源码。java的枚举类型,可以理解为一种特殊的java类

    计算机后端-Java-Java核心基础-第23章 枚举类与注解 07. Enum类中的常用方法.avi

    计算机后端-Java-Java核心基础-第23章 枚举类与注解 07. Enum类中的常用方法.avi

    Java enum(枚举)的使用

     enum 的全称为 enumeration, 是 JDK 1.5 中引入的新特性,存放在 java.lang 包中,在上面的这种情况下,enum能派上用场了。枚举类型的用途不仅如此,具体可用场景可看下面的介绍  1、常量  以前我们定义一...

    Java enum的用法详解.docx

    Java enum的用法详解

    Java enum的用法详解

    Java enum的用法详解,可作为开发api

Global site tag (gtag.js) - Google Analytics