改善Java程序建议11

建议11:实现序列化接口的类,显示声明UID

我们在编写实现Serializable接口的类的时候,IDE会提示:需要增加一个Serial Version ID。

  • 为什么要增加?
  • 它是怎么计算出来的?
  • 有什么用?
    类实现Serializable接口的目的是为了可持久化,比如网络传输或本地存储。
    实现序列化很简单:
public class Person implements Serializable {
  private String name;
  /*name属性的getter/setter方法省略*/
}

这里以Java消息服务方式传递该对象(即通过网络传递一个对象),定义在消息队列中数据类型为ObjectMessage,首先定义一个消息的生产者(Producer)。

public class Producer{
  public static void main(String[] args){
    Person person = new Person();
    person.setName("Kong");
    //序列化,保存到磁盘上,
    SerializationUtils .writeObject(person);
  }
}

这里引入了一个工具类SerializableUtils,其作用是对一个类进行序列化和反序列化,并存储在硬盘上。

public class SerializationUtils {
  private static String FILE_NAME = "D:/obj.bin";
  //序列化
  public static void writeObject(Serializable s){
    try{
            ObjectOutputStream oos = new ObjectOutputStream(new FlieOutputStream(FILE_NAME));
            oos.writeObject(s);
            oos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
  }

public static Object readObject(){
    Object obj  = null;
    //反序列化
    try{
          ObjectInputStream input = new ObjectInputStream(new FileInputStream(FILE_NAME));
          obj = input.readObject();
          input.close();
      } catch(Exception e) {
        e.printStackTrace();
      }
      return obj;
  }
}

通过对象序列化过程,把一个对象从内存块转化为可传输的数据流,然后通过网络发送消息到消费者那里,并进行反序列化,生成实例对象。

public class Consumer{
  public static void main (String[] args) throws Exception{
    //反序列化
    Person p = (Person) SerializationUtils.readObject();
    System.out.println("name = "+ p.getName()); 
  }
}

这是序列化和反序列化得典型DEMO。
有个问题:如果消息的生产者和消息的消费者 所参考的类(Person)有差异会出现什么情况?比如:消息生产者中的Person类增加一个age属性,而消费者没有增加该属性。在这种序列化和反序列化不一样的情况下,反序列化会报一个InvalidClassException异常,原因是序列化和反序列化所对应的类版本发生了变化,JVM不能把数据流转换为实例对象。
那么JVM是通过什么来判断一个类的版本类型?
通过SerialVersionUID,它可以隐式声明和显示声明,显示声明如下:
private static final long serialVersionUID = xxxxL
隐式声明即不声明,是编译器在 编译的时候通过包名,类名,继承关系、非私有的方法和属性,以及参数,返回值等各种计算出来,可以说是唯一的值。

JVM在反序列化时会比较数据流的serialVersionUID与类中的serialVersionUID是否一样,如果相同,则认为类没有发什么改变呢,可以把数据流load为实例对象:如果不相同,则会报InvalidClassException异常。

但是有时候类的改动很小,想把以前的对象反序列化过来,则需要显示的声明serialVersionUID,向JVM撒谎我的类没有改变。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • JAVA序列化机制的深入研究 对象序列化的最主要的用处就是在传递,和保存对象(object)的时候,保证对象的完整...
    时待吾阅读 13,753评论 0 24
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 135,828评论 19 139
  • 从三月份找实习到现在,面了一些公司,挂了不少,但最终还是拿到小米、百度、阿里、京东、新浪、CVTE、乐视家的研发岗...
    时芥蓝阅读 42,486评论 11 349
  • 于茉茉最怕一个人的夕阳,不论在哪里都是这样。许是少年时在乡下的时光,让她此生都免除不了对夕阳西下的恐慌。在她眼中的...
    小野莉香阅读 1,612评论 0 0

友情链接更多精彩内容