Serializable对象完全以它存储的二进制位为基础来反序列化,而不必调用构造器。对于一个Externalizable对象,所有的默认构造器都会被调用(包括在字段定义时的初始化),然后调用readExternal()方法来反序列化。因此,为了正常运行, 我们需要在writeExternal()将来自对象的重要信息写入(你要序列化的信息), 然后用readExternal()读取你之前序列化的对象信息。以两段代码为例:
import java.io.*; /** * Version: 3.0 * Author: pattywgm * Time: 17/7/21 下午2:53 * Desc: */ public class SerializationTest implements Serializable { private String name; private int age; public SerializationTest(){}; public SerializationTest(String name, int age){ this.name = name; this.age = age; } public String toString(){ return "Name is: "+ this.name + " and age is: " + this.age; } public static void main(String[] args){ SerializationTest serializationTest = new SerializationTest("wkl", 27); // 1) try { ObjectOutput output = new ObjectOutputStream(new FileOutputStream("se.pkl")); // 2) output.writeObject(serializationTest); ObjectInput input = new ObjectInputStream(new FileInputStream("se.pkl")); System.out.println(input.readObject().toString()); // 3) } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
上述代码实现了Serializable接口, 1)进行对象的实例化, 2)将对象序列化到本地,保存在se.pkl文件中 3)从本地反序列化对象,并打印输出。在此过程中不涉及对默认构造函数的调用。
1 import java.io.*; 2 3 /** 4 * Version: 3.0 5 * Author: pattywgm 6 * Time: 17/7/21 下午3:02 7 * Desc: 8 */ 9 public class ExternizationalTest implements Externalizable { 10 private String name = new String("zzk"); 11 private int age; 12 13 public ExternizationalTest(){}; 14 15 public ExternizationalTest(String name, int age){ 16 this.name = name; 17 this.age = age; 18 } 19 20 21 22 public void writeExternal(ObjectOutput out) throws IOException { 23 System.out.println("Write object...."); 24 out.writeObject(this.name); 25 out.writeInt(this.age); 26 } 27 28 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { 29 System.out.println("Read object...."); 30 this.name = (String)in.readObject(); 31 this.age = in.readInt(); 32 } 33 34 public String toString(){ 35 return "Name is: "+ this.name + " and age is: " + this.age; 36 } 37 38 public static void main(String[] args){ 39 ExternizationalTest externizationalTest = new ExternizationalTest("wkl", 27); // 1) 40 try { 41 ObjectOutput output = new ObjectOutputStream(new FileOutputStream("se1.pkl")); // 2) 42 output.writeObject(externizationalTest); 43 44 ObjectInput input = new ObjectInputStream(new FileInputStream("se1.pkl")); // 3) 45 System.out.println(input.readObject().toString()); 46 } catch (IOException e) { 47 e.printStackTrace(); 48 } catch (ClassNotFoundException e) { 49 e.printStackTrace(); 50 } 51 } 52 }
上述代码实现了Externalizable接口。
1)进行对象的实例化;
2)将对象序列化到本地,保存在se.pkl文件中, 此处在writeObject()后会调用writeExternal(ObjectOutput out)方法完成对象信息的序列化,即控制序列化对象的那些信息;
3)从本地反序列化对象,并打印输出。在此过程中会在readObject()后先调用默认构造器,以及第10行字段初始化,然后调用readExternal(ObjectInput in)完成对象信息的反序列化。
在实际的应用过程中, 对于一些敏感信息,我们并不希望被序列化,上述代码中虽然name, age都是private私有字段, 但通过序列化机制,外部依然可以获取到他们的值, 为了隐蔽掉对象的敏感信息, 我们可以使用transient关键字修饰敏感字段,这样在序列化对象时,将剔除对该字段的序列化。也可以在Externalizable对象中,通过writeExternal()进行显示序列化。如下:
import java.io.*; /** * Version: 3.0 * Author: pattywgm * Time: 17/7/21 下午2:53 * Desc: */ public class SerializationTest implements Serializable { private String name; private int age; private transient String password; // 该字段不会被序列化 public SerializationTest(){}; public SerializationTest(String name, int age, String password){ this.name = name; this.age = age; this.password = password; } public String toString(){ return "Name is: "+ this.name + " and age is: " + this.age + " and password is: " + this.password; } public static void main(String[] args){ SerializationTest serializationTest = new SerializationTest("wkl", 27, "123456"); try { ObjectOutput output = new ObjectOutputStream(new FileOutputStream("se.pkl")); output.writeObject(serializationTest); ObjectInput input = new ObjectInputStream(new FileInputStream("se.pkl")); System.out.println(input.readObject().toString()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
import java.io.*; /** * Version: 3.0 * Author: pattywgm * Time: 17/7/21 下午3:02 * Desc: */ public class ExternizationalTest implements Externalizable { private String name = new String("zjm"); private int age; private String password; // 该字段不会被序列化 public ExternizationalTest(){}; public ExternizationalTest(String name, int age, String password){ this.name = name; this.age = age; this.password = password; } public void writeExternal(ObjectOutput out) throws IOException { System.out.println("Write object...."); out.writeObject(this.name); out.writeInt(this.age); } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("Read object...."); this.name = (String)in.readObject(); this.age = in.readInt(); } public String toString(){ return "Name is: "+ this.name + " and age is: " + this.age + " and password is: " + this.password; } public static void main(String[] args){ ExternizationalTest externizationalTest = new ExternizationalTest("wkl", 27, "123456"); try { ObjectOutput output = new ObjectOutputStream(new FileOutputStream("se1.pkl")); output.writeObject(externizationalTest); ObjectInput input = new ObjectInputStream(new FileInputStream("se1.pkl")); System.out.println(input.readObject().toString()); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
如果此时我们在SerializationTest类中引用外部一个UserInfo对象,需要注意,该UserInfo对象必须是可序列化的,即实现了Serializable接口, 否则会在运行时报java.io.NotSerializableException: com.patty.jedis.demo.UserInfo错误。