Java序列化学习笔记

     Java 对象序列化为二进制文件的技术是 Java 系列技术中一个较为重要的技术点,在大多数情况下,只需要了解被序列化的类需要实现 Serializable 接口,使用 ObjectInputStream 和 ObjectOutputStream 进行序列化和反序列化即可。

     在工作中,经常会碰到序列化的情况,因为我们调用的东西不可能都在本地,往往需要通过RMI,一些远程接口调用。这样数据序列化的技术更显得重要。而java序列化技术为我们实现这些远程调用提供了技术保障。

 

一. 序列化的ID,请看如下代码

片段一:

 

public class Person implements Serializable{ private static final long serialVersionUID = 1L; private int age; private String name; private String mobile; private transient String address; //不被序列化的属性 } 

片段二:

public class Person implements Serializable{ private static final long serialVersionUID = 2L; private int age; private String name; private String mobile; private transient String address; //不被序列化的属性 } 

两个类除了serialVersionUID,其余完全一样,但这两个类是不能被序列化与反序列化的,所以在写程序时,实现了序列化的类,serialVersionUID一定要一致,否则客户端与服务端将不匹配,会因serialVersionUID不匹配导致意想不到的问题。当然也可以通过服务端强制更新serialVersionUID值,让客户端主动报错,来强制更新程序。

 

二.子类实现Serializable接口,而父类并没有实现Serializable 接口

父类:Person.java

/** * Created on 2011-3-11 * @author [email protected] * @version 1.0 */ public class Person { private int age; private String name; private String mobile; private transient String address; //不被序列化的属性 public Person(){ System.out.println("父类没有实现序列化接口时,默认构造器会被调用"); } public Person(String name,int age){ this.name = name; this.age = age; } public int getAge(){ return age; } public void setAge(int age){ this.age = age; } public String getName(){ return name; } public void setName(String name){ this.name = name; } public String getMobile(){ return mobile; } public void setMobile(String mobile){ this.mobile = mobile; } public void setAddress(String address) { this.address = address; } public String getAddress(){ return address; } }  

子类:Student.java

/** * Created on 2011-3-11 * @author [email protected] * @version 1.0 */ public class Student extends Person implements Serializable { public Student(String name, int age){ super(name, age); } private static final long serialVersionUID = 1L; public static String S_T = "static属性不能被序列化"; private int no; private String schoolName; public void setSchoolName(String schoolName){ this.schoolName = schoolName; } public String getSchoolName(){ return schoolName; } public void setNo(int no){ this.no = no; } public int getNo(){ return no; } } 

做如下测试:

/** * Created on 2011-3-11 * @author [email protected] * @version 1.0 */ public class SerializeTest { public static void main(String[] args){ Student student = new Student("shixing_11",27); student.setMobile("1515808XXXX"); //父类的属性 student.setAddress("浙江省杭州市"); //父类的属性 student.setNo(1111111); //子类自有属性 student.setSchoolName("XX理工大学"); //子类自有属性 serializeObject(student); //序列化方法 Student.S_T = "我是static,我的值被改"; deSerializeObject(); //反序列化 } private static void deSerializeObject() { try{ InputStream is = new FileInputStream("C://ss.ser"); ObjectInputStream ois = new ObjectInputStream(is); Student student = (Student)ois.readObject(); ois.close(); System.out.println(Student.S_T); System.out.println(student.getNo()); System.out.println(student.getSchoolName()); }catch (ClassNotFoundException e){ e.printStackTrace(); }catch (FileNotFoundException e){ e.printStackTrace(); } catch (IOException e){ e.printStackTrace(); } } public static void serializeObject(Person person){ try{ OutputStream os = new FileOutputStream("C://ss.ser"); ObjectOutputStream ois = new ObjectOutputStream(os); ois.writeObject(person); ois.close(); }catch (FileNotFoundException e){ e.printStackTrace(); }catch (IOException e){ e.printStackTrace(); } } } 

运行结果:

结论: 

 

1. 声明为 transient 型的属性是不被序列化的。

2. S_T属性的值被改变了,本来是序列时保存进去的是"static属性不能被序列化“,但读出来发现该值被改变,说明static声明的属性并没有     被写进文件里,所以声明为static型的属性是不被序列化的。

3. 子类实现Serializable接口,父类未实现Serializable接口,反序列化时父类的属性会被恢复成原始值,即int 0 ,String null.

    父类必须有无参的构造方法,因为如果父类实现了Serializable接口,则会直接从序列化过的文件里反序列化,读出来原来的对象即可,

    但若父类没有实现Serializable接口,则无法直接读取,所以只有调父类的默认构造器创建出该类的对象,再进行属性填充。

 

三.父类实现了Serializable接口的情况较简单,只需记住规则,如果父类实现了Serializable接口,则子类默认也可被序列化,不需要显式声明Serializable接口。

 

你可能感兴趣的:(java,String,OS,测试,Class,mobile)