标签: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]
看完这个结果应该比较好理解了。
标签:style blog io ar color os 使用 sp java
原文地址:http://www.cnblogs.com/punkisnotdead/p/4146208.html