一个对象产生以后其实是在内存中为其开辟了一个存储空间,方便存储信息。java
import java.io.Serializable ; public class Person implements Serializable{ private String name ; // 声明name属性 private int age ; // 声明age属性 public Person(String name,int age){ // 经过构造设置内容 this.name = name ; this.age = age ; } public String toString(){ // 覆写toString()方法 return "姓名:" + this.name + ";年龄:" + this.age ; } }
之后此类的对象,就能够被序列化了。变为二进制byte流。数组
import java.io.Serializable ; public class Person implements Serializable{ private static final long serialVersionUID = 1L;/*验证版本的一致性*/ private String name ; // 声明name属性 private int age ; // 声明age属性 public Person(String name,int age){ // 经过构造设置内容 this.name = name ; this.age = age ; } public String toString(){ // 覆写toString()方法 return "姓名:" + this.name + ";年龄:" + this.age ; } }
若是使用开发工具开发,没有编写此代码,则会出现一些安全警告信息。安全
import java.io.File ; import java.io.FileOutputStream ; import java.io.OutputStream ; import java.io.ObjectOutputStream ; public class SerDemo01{ public static void main(String args[]) throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定义保存路径 ObjectOutputStream oos = null ; // 声明对象输出流 OutputStream out = new FileOutputStream(f) ; // 文件输出流 oos = new ObjectOutputStream(out) ; oos.writeObject(new Person("张三",30)) ; // 保存对象 oos.close() ; // 关闭 } }
全部的对象拥有各自的属性值,可是全部的方法都是公共的,因此序列化对象的时候实际上序列化的就是属性。ide
import java.io.File ; import java.io.FileInputStream ; import java.io.InputStream ; import java.io.ObjectInputStream ; public class SerDemo02{ public static void main(String args[]) throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定义保存路径 ObjectInputStream ois = null ; // 声明对象输入流 InputStream input = new FileInputStream(f) ; // 文件输入流 ois = new ObjectInputStream(input) ; // 实例化对象输入流 Object obj = ois.readObject() ; // 读取对象 ois.close() ; // 关闭 System.out.println(obj) ; } }
import java.io.Serializable ;工具
public class Person implements Serializable{ private static final long serialVersionUID = 1L; private transient String name ; // 声明name属性,可是此属性不被序列化 private int age ; // 声明age属性 public Person(String name,int age){ // 经过构造设置内容 this.name = name ; this.age = age ; } public String toString(){ // 覆写toString()方法 return "姓名:" + this.name + ";年龄:" + this.age ; } }
操做代码:
import java.io.File ; import java.io.IOException ; import java.io.FileOutputStream ; import java.io.OutputStream ; import java.io.ObjectOutputStream ; import java.io.FileInputStream ; import java.io.InputStream ; import java.io.ObjectInputStream ; public class SerDemo04{ public static void main(String args[]) throws Exception{ ser() ; dser() ; } public static void ser() throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定义保存路径 ObjectOutputStream oos = null ; // 声明对象输出流 OutputStream out = new FileOutputStream(f) ; // 文件输出流 oos = new ObjectOutputStream(out) ; oos.writeObject(new Person("张三",30)) ; // 保存对象 oos.close() ; // 关闭 } public static void dser() throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定义保存路径 ObjectInputStream ois = null ; // 声明对象输入流 InputStream input = new FileInputStream(f) ; // 文件输入流 ois = new ObjectInputStream(input) ; // 实例化对象输入流 Object obj = ois.readObject() ; // 读取对象 ois.close() ; // 关闭 System.out.println(obj) ; } }
1)一旦变量被transient修饰,变量将再也不是对象持久化的一部分,该变量内容在序列化后没法得到访问。开发工具
2)transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量若是是用户自定义类变量,则该类须要实现Serializable接口。this
3)被transient关键字修饰的变量再也不能被序列化,一个静态变量无论是否被transient修饰,均不能被序列化。spa
第三点可能有些人很迷惑,由于发如今User类中的username字段前加上static关键字后,程序运行结果依然不变,即static类型的username也读出来为“Alexia”了,这不与第三点说的矛盾吗?其实是这样的:第三点确实没错(一个静态变量无论是否被transient修饰,均不能被序列化),反序列化后类中static型变量username的值为当前JVM中对应static变量的值,这个值是JVM中的不是反序列化得出的,不相信?好吧,下面我来证实:对象
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; publicclass TransientTest { public static void main(String[] args) { User user = new User(); user.setUsername("Alexia"); user.setPasswd("123456"); System.out.println("read before Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); try { ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("C:/user.txt")); os.writeObject(user); // 将User对象写进文件 os.flush(); os.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { // 在反序列化以前改变username的值 User.username = "jmwang"; ObjectInputStream is = new ObjectInputStream(new FileInputStream( "C:/user.txt")); user = (User) is.readObject(); // 从流中读取User的数据 is.close(); System.out.println("\nread after Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class User implements Serializable { private static final long serialVersionUID = 8294180014912103005L; public static String username; private transient String passwd; public String getUsername() { return username; } publicvoid setUsername(String username) { this.username = username; } public String getPasswd() { return passwd; } publicvoid setPasswd(String passwd) { this.passwd = passwd; } }
运行结果为:接口
read before Serializable: username: Alexia password: 123456 read after Serializable: username: jmwang password: null
这说明反序列化后类中static型变量username的值为当前JVM中对应static变量的值,为修改后jmwang,而不是序列化时的值Alexia。
思考下面的例子:
import java.io.Externalizable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream;
publicclass ExternalizableTest implements Externalizable { private transient String content = "是的,我将会被序列化,无论我是否被transient关键字修饰"; @Override publicvoid writeExternal(ObjectOutput out) throws IOException { out.writeObject(content); } @Override publicvoid readExternal(ObjectInput in) throws IOException, ClassNotFoundException { content = (String) in.readObject(); } publicstaticvoid main(String[] args) throws Exception { ExternalizableTest et = new ExternalizableTest(); ObjectOutput out = new ObjectOutputStream(new FileOutputStream( new File("test"))); out.writeObject(et); ObjectInput in = new ObjectInputStream(new FileInputStream(new File("test"))); et = (ExternalizableTest) in.readObject(); System.out.println(et.content); out.close(); in.close(); } }
content变量会被序列化吗?好吧,我把答案都输出来了,是的,运行结果就是:
是的,我将会被序列化,无论我是否被transient关键字修饰
这是为何呢,不是说类的变量被transient关键字修饰之后将不能序列化了吗?
咱们知道在Java中,对象的序列化能够经过实现两种接口来实现,若实现的是Serializable接口,则全部的序列化将会自动进行,若实现的是Externalizable接口,则没有任何东西能够自动序列化,须要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关。所以第二个例子输出的是变量content初始化的内容,而不是null。
若是要保存多个对象,则最好使用对象数组的形式完成。
import java.io.File ; import java.io.IOException ; import java.io.FileOutputStream ; import java.io.OutputStream ; import java.io.ObjectOutputStream ; import java.io.FileInputStream ; import java.io.InputStream ; import java.io.ObjectInputStream ; public class SerDemo05{ public static void main(String args[]) throws Exception{ Person per[] = {new Person("张三",30),new Person("李四",31), new Person("王五",32)} ; ser(per) ; Object o[] = (Object[])dser() ; for(int i=0;i<o.length;i++){ Person p = (Person)o[i] ; System.out.println(p) ; } } public static void ser(Object obj[]) throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定义保存路径 ObjectOutputStream oos = null ; // 声明对象输出流 OutputStream out = new FileOutputStream(f) ; // 文件输出流 oos = new ObjectOutputStream(out) ; oos.writeObject(obj) ; // 保存对象 oos.close() ; // 关闭 } public static Object[] dser() throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定义保存路径 ObjectInputStream ois = null ; // 声明对象输入流 InputStream input = new FileInputStream(f) ; // 文件输入流 ois = new ObjectInputStream(input) ; // 实例化对象输入流 Object obj[] = (Object[])ois.readObject() ; // 读取对象 ois.close() ; // 关闭 return obj ; } }