java序列化(一)
今天我们来探讨一下java的序列化与反序列化。之前对此一直有概念,但是并没有真正的去测试。大家都知道,所谓的序列化就是把java代码读取到一个文件中,反序列化就是从文件中读取出对象。在网络传输过程中,我们也需要对对象进行序列化,因为一个对象是不能进行传输的。下面先上代码
package serializable; import java.io.*; public class SerializableTest implements Serializable { private static final Long serialVersionUID = 1L; private String name; public String sex; protected int age; private static int id; transient private float height; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public static int getId() { return id; } public static void setId(int id) { SerializableTest.id = id; } public float getHeight() { return height; } public void setHeight(float height) { this.height = height; } public static void main(String[] args) throws Exception { serializable(); deSerializable(); } /** * 序列化 * @throws IOException */ private static void serializable() throws IOException { SerializableTest serializableTest = new SerializableTest(); serializableTest.setAge(25); serializableTest.setId(122528); serializableTest.setName("张三"); serializableTest.setSex("男"); serializableTest.setHeight(175); FileOutputStream fos = new FileOutputStream("serializableTest.txt"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(serializableTest); oos.flush(); oos.close(); } /** * 反序列化 * @throws Exception */ public static void deSerializable() throws Exception{ FileInputStream fis = new FileInputStream("serializableTest.txt"); ObjectInputStream ois = new ObjectInputStream(fis); SerializableTest serializableTest = (SerializableTest) ois.readObject(); System.out.println("serializableTest.getAge() = " + serializableTest.getAge()); System.out.println("serializableTest.getName() = " + serializableTest.getName()); System.out.println("serializableTest.getSex() = " + serializableTest.getSex()); System.out.println("serializableTest.getHeight() = " + serializableTest.getHeight()); System.out.println("serializableTest.getId() = " + serializableTest.getId()); } }
此类中,包括了private、public、protected、static和transient修饰的属性,我们先看下运行结果
serializableTest.getAge() = 25 serializableTest.getName() = 张三 serializableTest.getSex() = 男 serializableTest.getHeight() = 0.0 serializableTest.getId() = 122528
可以发现transient修饰的属性并没有被序列化,这也是我们所认知的。但是static修饰的属性也不应该被序列化才对,现在对象已经被我们读到文件中了,在单独执行一次反序列化方法。
public static void main(String[] args) throws Exception { //serializable(); deSerializable(); }
执行结果如下:
serializableTest.getAge() = 25 serializableTest.getName() = 张三 serializableTest.getSex() = 男 serializableTest.getHeight() = 0.0 serializableTest.getId() = 0
现在得到的Id的值是0,也就是这个值并没有被序列化存储到文件中。
最后再说一下序列化版本号的意义。在我的理解看来,次版本号就是为了保证程序的稳定性,如果我们不声明的话,如果开始的一个对象序列化时,会为我们自动生成一个版本,如果后面我们修改了此类,那么在反序列化的时候,会发生版本不一致的问题。所以一般我们会声明成一个定值,这样就能防止上述问题。我们可以把版本代码注释掉,运行一下反序列化结果如下:
Exception in thread "main" java.io.InvalidClassException: serializable.SerializableTest; local class incompatible: stream classdesc serialVersionUID = 4564223277371155727, local class serialVersionUID = 5130976784646098676 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:699) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1885) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1751) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2042) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1573) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431) at serializable.SerializableTest.deSerializable(SerializableTest.java:89) at serializable.SerializableTest.main(SerializableTest.java:60)