码迷,mamicode.com
首页 > 编程语言 > 详细

java 序列化详解(二)

时间:2014-12-05 12:22:41      阅读:247      评论:0      收藏:0      [点我收藏+]

标签:style   blog   io   ar   color   os   使用   sp   java   

接着前面的文章说,当任何一个类继承Serializable 这个接口时,Eclipse经常会有黄色惊叹号提示。

提示内容如下:

The serializable class Person does not declare a static final serialVersionUID field of type long

点开以后有2个选择 一个是

Adds a default serial version ID to the selected type.

Use this option to add a user-defined ID in combination with
custom serialization code if the type did undergo structural
changes since its first release.

还有一个是

Adds a generated serial version ID to the selected type.

Use this option to add a compiler-generated ID if the type did
not undergo structural changes since its first release.

 

那么这个serialVersionUID  是干嘛的?

简单提一下 ,可以把这个

 

/**
*
*/
private static final long serialVersionUID = 1L;

 

Eclipse帮我们生成的这个语句解释一下。

 

实际上,java序列化呢,主要的应用场景就是 rmi。远程接口调用。

我举个例子,前面我们写的那个例子。把她序列化和反序列化 这个过程分开

放在2个工程里面,(要注意虽然是2个工程但是包要一样),

运行以后程序是正常的,但是你要注意 如果此时你2个工程的person类的

serialVersionUID  这个值如果不一样。你就会发现在反序列化的时候失败了。

只有当这个值相等的时候 序列化和反序列化才会成功。

 

其实这个值主要就是用来强制客户端更新接口用的。(RMI里经常使用)

比如客户端有个类A,服务器端有个类也是A。这个时候2个端用rmi进行通信,

假设服务器端这个类A 修改了某些内容比如增加或删除了一个字段,这个时候你怎么通知

客户端呢,你就把serialVersionUID  这个值修改成和客户端不一样的,这样在序列化或者反序列化的

时候就会出错,如此一来 客户端就知道,噢,序列化出错要更新接口了。

 

此外,前面的那个文章也说明了,序列化的过程默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法

当然我们也可以手动写方法来调用,writeObject 和 readObject 方法可以允许用户控制序列化的过程,手动控制除了能更好的控制序列化所消耗的事件以外,

还有一个优点是可以加密,比如我们要序列化一个 用户的用户名和密码,你默认序列化的话,是有可能被抓取的,但是如果你手动序列化在里面对密码进行

加密,然后在反序列化的时候解密,就非常安全了。

 

再看一段代码。

 

 1 package com.burning.test;
 2 
 3 import java.io.Serializable;
 4 
 5 public class Person implements Serializable {
 6 
 7     public static final int STATIC_VALUE =100;
 8     
 9     
10     @Override
11     public String toString() {
12         return "Person [name=" + name + ", age=" + age + "]";
13     }
14 
15     public String getName() {
16         return name;
17     }
18 
19     public void setName(String name) {
20         this.name = name;
21     }
22 
23     public int getAge() {
24         return age;
25     }
26 
27     public void setAge(int age) {
28         this.age = age;
29     }
30 
31     private String name;
32 
33     private int age;
34 
35 }

然后看看main

 

 1 package com.burning.test;
 2 
 3 import java.io.File;
 4 import java.io.FileInputStream;
 5 import java.io.FileNotFoundException;
 6 import java.io.FileOutputStream;
 7 import java.io.IOException;
 8 import java.io.ObjectInputStream;
 9 import java.io.ObjectOutputStream;
10 
11 public class TestMain {
12 
13     public static void main(String[] args) {
14         // TODO Auto-generated method stub
15         File file = new File("person2.out");
16         ObjectInputStream oin = null;
17         ObjectOutputStream oout = null;
18         try {
19             oout = new ObjectOutputStream(new FileOutputStream(file));
20             Person person = new Person();
21             oout.writeObject(person);
22             oout.flush();
23 
24             System.out.println("第1次写完以后" + file.length());
25             oout.writeObject(person);
26             System.out.println("第2次写完以后" + file.length());
27             oout.close();
28             oin = new ObjectInputStream(new FileInputStream(file));
29             Object obj = oin.readObject();
30             Object obj2 = oin.readObject();
31             System.out.println(obj == obj2);
32 
33         } catch (FileNotFoundException e) {
34             // TODO Auto-generated catch block
35             e.printStackTrace();
36         } catch (IOException e) {
37             // TODO Auto-generated catch block
38             e.printStackTrace();
39         } catch (ClassNotFoundException e) {
40             // TODO Auto-generated catch block
41             e.printStackTrace();
42         } finally {
43             try {
44                 oout.close();
45             } catch (IOException e) {
46                 // TODO Auto-generated catch block
47                 e.printStackTrace();
48             }
49             try {
50                 oin.close();
51             } catch (IOException e) {
52                 // TODO Auto-generated catch block
53                 e.printStackTrace();
54             }
55 
56         }
57 
58     }
59 }

运行一下程序。结果为

 

第1次写完以后83
第2次写完以后88
true。

 

这个地方运行结果一目了然,我们发现,Java 序列化机制为了节省磁盘空间,具有特定的存储规则,当写入文件的为同一对象时,并不会再将对象的内容进行存储,而只是再次存储一份引用,

上面增加的 5 字节的存储空间就是新增引用和一些控制信息的空间。反序列化时,恢复引用关系,使得清单 3 中的 t1 和 t2 指向唯一的对象,二者相等,输出 true。该存储规则极大的节省了存储空间。

 

然后我们再修改一下主类

package com.burning.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TestMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        File file = new File("person2.out");
        ObjectInputStream oin = null;
        ObjectOutputStream oout = null;
        try {
            oout = new ObjectOutputStream(new FileOutputStream(file));
            Person person = new Person();
            person.setAge(10);
            oout.writeObject(person);
            oout.flush();

            System.out.println("第1次写完以后" + file.length());
            person.setAge(20);
            oout.writeObject(person);
            System.out.println("第2次写完以后" + file.length());
            oout.close();
            oin = new ObjectInputStream(new FileInputStream(file));
            Object obj = oin.readObject();
            Object obj2 = oin.readObject();
            System.out.println(obj.toString());
            System.out.println(obj2.toString());


        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                oout.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                oin.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }
}

看一下运行结果

 

第1次写完以后83
第2次写完以后88
Person [name=null, age=10]
Person [name=null, age=10]

 

我们就会发现结果是这样的,因为第一次对象保存完毕以后  你虽然修改了这个对象的值,但是你在第二次序列化对象的时候 因为这2个对象引用相等 所以不会更改值,只会保存一部分引用

所以会得出一个比较奇怪的结果~这个地方要好好理解下

再次修改main 看看运行结果

 

package com.burning.test;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class TestMain {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        File file = new File("person4.out");
        ObjectInputStream oin = null;
        ObjectOutputStream oout = null;
        try {
            oout = new ObjectOutputStream(new FileOutputStream(file));
            Person person = new Person();
            person.setAge(10);
            oout.writeObject(person);
            oout.flush();

            System.out.println("第1次写完以后" + file.length());
            Person person2 = new Person();
            person2.setAge(20);
            oout.writeObject(person2);
            System.out.println("第2次写完以后" + file.length());
            oout.close();
            oin = new ObjectInputStream(new FileInputStream(file));
            Object obj = oin.readObject();
            Object obj2 = oin.readObject();
            System.out.println(obj.toString());
            System.out.println(obj2.toString());


        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                oout.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            try {
                oin.close();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

        }

    }
}

 

这个结果 就是 

第1次写完以后83
第2次写完以后94
Person [name=null, age=10]
Person [name=null, age=20]

看完这个结果应该比较好理解了。

 

java 序列化详解(二)

标签:style   blog   io   ar   color   os   使用   sp   java   

原文地址:http://www.cnblogs.com/punkisnotdead/p/4146208.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!