1.序列化的定义
把对象转化为字节序列的过程称为对象的序列化。
把字节序列恢复为对象的过程称为独享的反序列化。
2.序列化的作用
主要用途有两种:
1、把对象的字节序列永久的保存到硬盘上。
2、在网络上传输对象的字节序列。
3.JDK序列化API
java.io.ObjectOutputStream代表对象输出流,它的writeObject(Objectobj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
对象序列化的步骤:
1、创建一个对象输出流
2、通过writeObject()方法写入对象
对象反序列化的步骤:
1、创建一个对象输入流
2、通过readObject()方法读取对象
对象序列化的例子:
/**
* 序列化测试
* @author SN22010
*/
public classSerializableTest {
@Ignore
@Test
public void testSerialize() throws FileNotFoundException,IOException {
PersonTestperson = newPersonTest("liushuai", "123456");
System.out.println("Before Serialize:");
System.out.println(person.toString());
ObjectOutputStreamos = newObjectOutputStream(new FileOutputStream(new File("D:/Person.txt")));
os.writeObject(person);
System.out.println("对象序列化成功!");
os.close();
}
@Test
public void testReadSerialize() throws FileNotFoundException,IOException, ClassNotFoundException {
ObjectInputStreamis = newObjectInputStream(new FileInputStream(new File("D:/Person.txt")));
System.out.println("反序列化前:");
PersonTestperson = (PersonTest)is.readObject();
System.out.println(person.toString());
}
}
执行结果:
反序列化前:
PersonTest [username=liushuai,password=123456]
其中PersonTest为:
public classPersonTest implementsSerializable{
private static final long serialVersionUID= 1L;
private String username;
private String password;
public PersonTest() {
}
public PersonTest(Stringusername, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(Stringusername) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(Stringpassword) {
this.password = password;
}
@Override
public String toString() {
StringBuilderbuilder = newStringBuilder();
builder.append("PersonTest [username=");
builder.append(username);
builder.append(", password=");
builder.append(password);
builder.append("]");
return builder.toString();
}
}
4. serialVersionUID的作用
serialVersionUID的作用主要是序列化后添加一个字段或者方法,可以正常反序列化。例如:PersonTest中添加一条属性sex,执行反序列化结果为:
反序列化后:
PersonTest [username=liushuai,password=123456, sex=null]
这种是类中包含serialVersionUID的情况;当去掉serialVersionUID后执行结果为:
java.io.InvalidClassException:javaprojectTest.javaIO.PersonTest; local class incompatible: stream classdescserialVersionUID = 1, local class serialVersionUID = 8864783882401198096
atjava.io.ObjectStreamClass.initNonProxy(Unknown Source)
atjava.io.ObjectInputStream.readNonProxyDesc(Unknown Source)
atjava.io.ObjectInputStream.readClassDesc(Unknown Source)
atjava.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
atjava.io.ObjectInputStream.readObject0(Unknown Source)
atjava.io.ObjectInputStream.readObject(Unknown Source)
atjavaprojectTest.javaIO.SerializableTest.testReadSerialize(SerializableTest.java:38)
atsun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
atsun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
atsun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
atjava.lang.reflect.Method.invoke(Unknown Source)
atorg.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
atorg.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
atorg.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
atorg.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
atorg.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271)
atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70)
atorg.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
atorg.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
atorg.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
atorg.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
atorg.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
atorg.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
atorg.junit.runners.ParentRunner.run(ParentRunner.java:309)
atorg.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
atorg.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
atorg.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
报错内容为:字符流中的serialVersionUID为1;而类中的serialVersionUID为: 8864783882401198096因而报错。
出现serialVersionUID=8864783882401198096的原因是在本地类中没有指定固定的序列号,java在编译时编译器会生成一条Uid。
类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值。这样也可以避免上方错误。
5. transient关键字作用
Transient可以加在类中某个字段之前,这样可以避免此字段序列化。例如:
private transientString sex;反序列化后执行结果为:
PersonTest [username=liushuai, password=123456, sex=null]
6. Externalizable
此接口是Serializable的拓展,在接口中存在两个方法: readExternal与writeExternal;
这两种方法可以确定哪些字段可以被序列化,哪些不需要,在这个接口下transient不起作用,例子如下:
@Override
public voidreadExternal(ObjectInput in) throws IOException,
ClassNotFoundException{
this.sex = (String)in.readObject();
this.username =(String)in.readObject();
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeObject(this.sex);
out.writeObject(this.username);
}
这两个属性是按照顺序赋值的。执行结果如下:
PersonTest[username=刘帅, password=null, sex=男]
参考
博客:
http://www.cnblogs.com/dukc/p/4817822.html;
http://www.cnblogs.com/xdp-gacl/p/3777987.html
http://www.cnblogs.com/lanxuezaipiao/p/3369962.html