`
MauerSu
  • 浏览: 493329 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

Java中Enum类型的序列化

 
阅读更多
源:http://mysun.iteye.com/blog/1581119
评:

大概意思就是说,在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中
enum内部变量 不能被序列化进去


在Java中,对Enum类型的序列化与其他对象类型的序列化有所不同,今天就来看看到底有什么不同。下面先来看下在Java中,我们定义的Enum在被编译之后是长成什么样子的。
Java代码:
Java代码  收藏代码
public enum FruitEnum { 
    APPLE, ORAGE 


上面的代码定义了一个FruitEnum类型,是最简单形式的,下面我们来看看编译之后的字节码。
字节码:
Java代码  收藏代码
public final class com.taobao.tianxiao.FruitEnum extends java.lang.Enum 
.... 
.... 
.... 

public static final com.taobao.tianxiao.FruitEnum APPLE; 
 
public static final com.taobao.tianxiao.FruitEnum ORAGE; 
 
static {}; 
  Code: 
   Stack=4, Locals=0, Args_size=0 
   0:   new #1; //class com/taobao/tianxiao/FruitEnum 
   3:   dup 
   4:   ldc #13; //String APPLE 
   6:   iconst_0 
   7:   invokespecial   #14; //Method "<init>":(Ljava/lang/String;I)V 
   10:  putstatic   #18; //Field APPLE:Lcom/taobao/tianxiao/FruitEnum; 
   13:  new #1; //class com/taobao/tianxiao/FruitEnum 
   16:  dup 
   17:  ldc #20; //String ORAGE 
   19:  iconst_1 
   20:  invokespecial   #14; //Method "<init>":(Ljava/lang/String;I)V 
   23:  putstatic   #21; //Field ORAGE:Lcom/taobao/tianxiao/FruitEnum; 
   26:  iconst_2 
   27:  anewarray   #1; //class com/taobao/tianxiao/FruitEnum 
   30:  dup 
   31:  iconst_0 
   32:  getstatic   #18; //Field APPLE:Lcom/taobao/tianxiao/FruitEnum; 
   35:  aastore 
   36:  dup 
   37:  iconst_1 
   38:  getstatic   #21; //Field ORAGE:Lcom/taobao/tianxiao/FruitEnum; 
   41:  aastore 
   42:  putstatic   #23; //Field ENUM$VALUES:[Lcom/taobao/tianxiao/FruitEnum; 
   45:  return 
  LineNumberTable:  
   line 4: 0 
   line 3: 26 
 
public static com.taobao.tianxiao.FruitEnum[] values(); 
  Code: 
   Stack=5, Locals=3, Args_size=0 
   0:   getstatic   #23; //Field ENUM$VALUES:[Lcom/taobao/tianxiao/FruitEnum; 
   3:   dup 
   4:   astore_0 
   5:   iconst_0 
   6:   aload_0 
   7:   arraylength 
   8:   dup 
   9:   istore_1 
   10:  anewarray   #1; //class com/taobao/tianxiao/FruitEnum 
   13:  dup 
   14:  astore_2 
   15:  iconst_0 
   16:  iload_1 
   17:  invokestatic    #31; //Method java/lang/System.arraycopy:(Ljava/lang/Object;ILjava/lang/Object;II)V 
   20:  aload_2 
   21:  areturn 
  LineNumberTable:  
   line 1: 0 
 
public static com.taobao.tianxiao.FruitEnum valueOf(java.lang.String); 
  Code: 
   Stack=2, Locals=1, Args_size=1 
   0:   ldc #1; //class com/taobao/tianxiao/FruitEnum 
   2:   aload_0 
   3:   invokestatic    #39; //Method java/lang/Enum.valueOf:(Ljava/lang/Class;Ljava/lang/String;)Ljava/lang/Enum; 
   6:   checkcast   #1; //class com/taobao/tianxiao/FruitEnum 
   9:   areturn 
  LineNumberTable:  
   line 1: 0 


上面的字节码已经去掉的常量池部分,但是即便如此,在我们的源代码中如此简单的一个FruitEnum类,编译器居然为我们产生了这么多的字节码,哇哦~~~~~~~~
仔细地看这段代码, 编译器是在为我们创建一个类,这个类继承自 java.lang.Enum ,有两个公共的、静态的、被声明成final的属性,它们的类型就是我们定义的FruitEnum。同时,编译器还生成了一个静态初始话器,就是字节码中static{};这一行下面的代码,其中的字节码创建了两个FruitEnum对象,同时分别赋值给APPLE和ORANGE这两个属性,调用的构造函数是定义在 java.lang.Enum中的protected Enum(String name, int ordinal)方法。在创建完成两个FruitEnum对象并且分别赋值给APPLE和ORIGIN之后,还创建了一个名叫ENUM$VALUES的数组,然后把APPLE和ORIGIN按照定义的顺序放如这个数组中。
除了这个静态初始化器之外,编译器还为我们生成了两个静态方法,values()和 valueOf(java.lang.String)方法。其中values()方法将ENUM$VALUES数组拷贝一份然后返回,而valueOf(java.lang.String)方法则会调用java.lang.Enum类中的valueOf方法,其作用是根据参数名找到对应的具体的枚举对象,如果找不到的话会抛出一个IllegalArgumentException异常。
从上面的叙述可以看到,我们定义的枚举类型,经过编译器的处理最终会编程一个对象的定义,其中的枚举变量其实就是类的静态变量,因此Java中的枚举类型其实是具有很多对象的特性的,只不过平时我们都不太用到,比如枚举可以实现接口(不能继承)、定义方法等等。为了保证枚举类型像Java规范中所说的那样,每一个枚举类型极其定义的枚举变量在JVM中都是唯一的,在枚举类型的序列化和反序列化上,Java做了特殊的规定。原文如下(摘自Java的序列化规范):
引用

Enum constants are serialized differently than ordinary serializable or externalizable objects. The serialized form of an enum constant consists solely of its name; field values of the constant are not present in the form. To serialize an enum constant, ObjectOutputStream writes the value returned by the enum constant's name method. To deserialize an enum constant, ObjectInputStream reads the constant name from the stream; the deserialized constant is then obtained by calling the java.lang.Enum.valueOf method, passing the constant's enum type along with the received constant name as arguments. Like other serializable or externalizable objects, enum constants can function as the targets of back references appearing subsequently in the serialization stream.
The process by which enum constants are serialized cannot be customized: any class-specific writeObject, readObject, readObjectNoData, writeReplace, and readResolve methods defined by enum types are ignored during serialization and deserialization. Similarly, any serialPersistentFields or serialVersionUID field declarations are also ignored--all enum types have a fixedserialVersionUID of 0L. Documenting serializable fields and data for enum types is unnecessary, since there is no variation in the type of data sent.

大概意思就是说,在序列化的时候Java仅仅是将枚举对象的name属性输出到结果中,反序列化的时候则是通过java.lang.Enum的valueOf方法来根据名字查找枚举对象。同时,编译器是不允许任何对这种序列化机制的定制的,因此禁用了writeObject、readObject、readObjectNoData、writeReplace和readResolve等方法。下面我们来看看反序列化时候被调用的那个valueOf方法长什么样子。
java代码:
Java代码  收藏代码
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); 
    } 

从代码中可以看到,代码会尝试从调用enumType这个Class对象的enumConstantDirectory()方法返回的map中获取名字为name的枚举对象,如果不存在就会抛出异常。再进一步跟到enumConstantDirectory()方法,就会发现到最后会以反射的方式调用enumType这个类型的values()静态方法,也就是上面我们看到的编译器为我们创建的那个方法,然后用返回结果填充enumType这个Class对象中的enumConstantDirectory属性。
在了解了Java如何处理枚举的定义以及序列化和反序列化枚举类型之后,我们就需要在系统或者类库升级时,对其中定义的枚举类型多加注意,为了保持代码上的兼容性,如果我们定义的枚举类型有可能会被序列化保存(放到文件中、保存到数据库中,进入分布式内存缓存中),那么我们是不能够删除原来枚举类型中定义的任何枚举对象的,否则程序在运行过程中,JVM就会抱怨找不到与某个名字对应的枚举对象了。另外,在远程方法调用过程中,如果我们发布的客户端接口返回值中使用了枚举类型,那么服务端在升级过程中就需要特别注意。如果在接口的返回结果的枚举类型中添加了新的枚举值,那就会导致仍然在使用老的客户端的那些应用出现调用失败的情况。因此,针对以上两种情况,应该尽量避免使用枚举,如果实在要用,也需要仔细设计,因为一旦用了枚举,有可能会给后期维护带来隐患。
分享到:
评论

相关推荐

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

    Xson是一个Java对象序列化和反序列化程序。支持Java对象到字节数组的序列化,和从字节数组到Java对象的反序列化。 Maven:  &lt;groupId&gt;com.github.xsonorg&lt;/groupId&gt;  &lt;artifactId&gt;xson-core  &lt;version&gt;1.0.1 ...

    Gson 枚举类型的统一序列化/反序列化处理

    实现了通过gson对enum的自定义转化过程,不需要预先定义enmu,并且不需要修改gson源码,在框架顶层处理基本可以达到对enum的抽象管理。

    枚举类实现单例,并且解决序列化给前端展示的问题.zip

    代码中包含枚举类的基本使用,和完整的请求示例。 主要实现了枚举类创建单例后,将结果返回给前端。 看过一些其他人的实现,都比较麻烦。这是结合一些博主的代码,摸索出来的比较方便的方案。 缺点就是 多线程下会...

    Java基础知识点总结.docx

    对象的序列化 310 Java两种线程类:Thread和Runnable 315 Java锁小结 321 java.util.concurrent.locks包下常用的类 326 NIO(New IO) 327 volatile详解 337 Java 8新特性 347 Java 性能优化 362

    java语言程序设计 java编程笔记 由浅入深的笔记 共32份 全套资源.rar

    java序列化.docx Math类.docx Object(对象).docx operator(运算符).docx Properties.docx return语句的例子.docx Scanner和if语法.docx static.docx 毕向东视频的笔记.docx 参数传递.docx 第二周所学总结.docx ...

    Java开发详解.zip

    031217_【第12章:JAVA IO】_对象序列化笔记.pdf 031218_〖第12章:JAVA IO〗_实例操作—单人信息管理程序笔记.pdf 031219_〖第12章:JAVA IO〗_实例操作:投票程序笔记.pdf 031301_【第13章:Java类集】_认识类集、...

    整理后java开发全套达内学习笔记(含练习)

    序列化,串行化 ['siәriәlaiz]'(serializable adj.)(deserialize反序列化,反串行化) Socket [java] 网络套接字['sɒkit] stack n.堆栈 [stæk] (对应 heap 堆) statement 程序语句; 语句 ['steitmәnt]' n. 陈述,...

    java解析json方法总结

    这里推荐使用:阿里巴巴FastJson是一个Json处理工具包,包括“序列化”和“反序列化”两部分,它具备如下特征: 速度最快,测试表明,fastjson具有极快的性能,超越任其他的Java Json parser。包括自称最快的...

    Java开发技术大全 电子版

    7.7序列化261 7.8本章小结264 第4篇Java中的高级技术 第8章Java的多线程机制266 8.1线程的概念266 8.1.1多线程的特点266 8.1.2线程的状态267 8.2Thread类268 8.2.1Thread类的构造方法268 8.2.2Thread类的...

    fastjson-1.2.41.jar 非常好用的JSON转换依赖包

    1.FastJson数度快,无论序列化和反序列化,都是当之无愧的fast 2.功能强大(支持普通JDK类包括任意Java Bean Class、Collection、Map、Date或enum) 3.零依赖(没有依赖其它任何类库) 3.FastJson的简单说明: FastJson...

    阿里巴巴编码规范 基础技能认证 考题分析(考题+答案).docx

    A .POJO类中的任何布尔类型的变量,都不要加is,因为部分框架解析时有可能会出现序列化错误。 B .包名统一使用单数形式,如:com.alibaba.mpp.util。 C .中括号是数组类型的一部分,数组定义如下:String[] ...

    commons-lang3-3.1 API

    SerializationUtils – 用于处理对象序列化,提供比一般Java序列化更高级的处理能力; StringEscapeUtils – 用于正确处理转义字符,产生正确的Java、JavaScript、HTML、XML和SQL代码; StringUtils – 处理String的...

    json转换工具类

    1.FastJson速度快,无论序列化和反序列化,都是当之无愧的fast; 2.功能强大(支持普通JDK类包括任意Java Bean Class、Collection、Map、Date或enum); 3.零依赖(没有依赖其它任何类库)。

    fastjson-1.1.6.jar

    阿里巴巴FastJson是一个Json处理工具包,包括“序列化”和“反序列化”两部分,它具备如下特征: 速度最快,测试表明,fastjson具有极快的性能,超越任其他的Java Json parser。包括自称最快的JackJson; 功能强大,...

    day020-继承加强和设计模式代码和笔记.rar

    一般用饿汉模式,如果有序列化(自己百度扩展)要求,用枚举。 7. 不需要频繁创建对象的时候;不允许多个对象 用单例 2. 装饰者模式:(了解) 装饰者模式指的是在不必改变原类(Input)文件和...

Global site tag (gtag.js) - Google Analytics