《Java编程思想》学习笔记15——对象序列化
2015-06-03 16:24
555 查看
Java的对象序列化是一个轻量级的持久化过程,序列化时,可以将java对象以字节序列形式写入硬盘、数据库或者通过网络传输到另一个JVM等等,反序列化是读取序列化的文件,将其在JVM中还原为java对象的过程。
1.简单的序列化和反序列化:
最简单的序列化是对象实现Serializable序列化接口,这个接口是一个标记接口,不需要实现任何方法。
下面的小例子简单展示java对象序列化和反序列化的过程:
[java] view
plaincopy
import java.io.*;
//简单的测试对象
public class TestObject implements Serializable{}
import java.io.*;
//序列化
public class SerializeObject{
public static void main(String[] args)throws Exception{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“x.file”));
TestObject obj = new TestObject();
//将TestObject对象序列化到x.file文件中
out.write(obj);
}
}
import java.io.*;
//反序列化
public class DeserializeObject{
public static void main(String[] args)throw Exception{
ObjectInputStream in = new ObjectInputStream(new FileInputStream(“x.file”));
Object myObj = in.readObject();
System.out.println(myObj.getClass());
}
}
输出结果:
class TestObject
在序列化时,使用ObjectOutputStream将对象序列化写出,反序列化时,使用ObjectInputStream将对象反序列化读入。
注意:反序列化对象使用时,对象的class文件必须在classpath中,否则,JVM找不到对象的class文件会抛出ClassNotFoundException。
2.序列化控制:
默认的Serializable序列化是将对象整体序列化,但是对于一些特殊的需求例如:序列化部分对象或者反序列化部分对象的情况,就必须使用Externalizable接口来代替Serializable接口,Externalizable的writeExternal()和readExternal()方法可以实现对序列化的控制,这两个方法在对象序列化和反序列化时自动调用,例子如下:
[java] view
plaincopy
import java.io.*;
class Blip1 implements Externalizable{
public Blip1(){
System.out.println(“Blip1 Constructor”);
}
public void writeExternal(ObjectOutput out)throws IOException{
System.out.println(“Blip1.writeExternal”);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
System.out.println(Blip1.readExternal);
}
}
class Blip2 implements Externalizable{
Blip1(){
System.out.println(“Blip2 Constructor”);
}
public void writeExternal(ObjectOutput out)throws IOException{
System.out.println(“Blip2.writeExternal”);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
System.out.println(Blip2.readExternal);
}
}
public class Blips{
public static void main(String[] args)throws IOException, ClassNotFoundException{
System.out.println(“Constructing objects:”);
Blip1 b1 = new Blip1();
Blip2 b2 = new Blip2();
//序列化
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“Blips.out”));
System.out.println(“Saving objects:”);
o.writeObject(b1);
o.writeObject(b2);
//反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream(“Blips.out”));
System.out.println(“Recovering b1:”);
b1 = (Blip1)in.readObject();
//由于Blip2的默认无参数构造方法不是public的,所以会抛异常
//System.out.println(“Recovering b2:”);
//b2 = (Blip2)in.readObject();
}
}
输出结果:
Constructing objects:
Blip1 Constructor
Blip2 Constructor
Saving objects:
Blip1.writeExternal
Blip2.writeExternal
Recovering b1:
Blip1 Constructor
Blip1.readExternal
注意:由于对象在反序列化时需要调用默认的public的无参数构造方法创建对象,所以Blip2非public类型无参数构造方法无法反序列化。所以使用Externalizable序列化和反序列化时,对象必须要有public类型的无参数构造方法,这一点是Externalizable和Serializable的区别。
Serializable和Externlizable反序列化的区别:
(1).Serializable的反序列化是通过序列化的字节数组序列进行反序列化的。对象的序列化的反序列化都是自动进行的。
(2).Externalizable的反序列化是通过调用默认的构造方法进行的。对象的序列化需要使用writeExternal()显式控制,对象的反序列化需要使用readExternal()显式控制,不是自动进行的。
3. Externlizable序列化高级:
使用Externlizable序列化和反序列化对象时,readExternal()和writeExternal()方法可以对象中指定字段进行初始化,例子如下:
[java] view
plaincopy
import java.io.*;
public class Test implements Externalizable{
private int i;
private String s;
public Test(){
System.out.println(“Test Constructor”);
}
public Test(String x, int a){
System.out.println(“Test(String x, int a)”);
i = a;
s = x;
}
public void toString(){
return s + i;
}
public void writeExternal(ObjectOutput out)throws IOException{
System.out.println(“Test.writeExternal”);
out.writeObject(s);
out.writeInt(i);
}
public void readExternal(ObjectInput in)throws IOException, ClassNotFoundException{
System.out.println(“Test.readExternal”);
s = (String)in.readObject();
i = in.readInt();
}
public static void main()throws IOException, ClassNotFoundException{
System.out.println(“Constructing objects:”);
Test t1 = new Test(“A String”, 47);
Test t2 = new Test();
System.out.println(t1);
System.out.println(t2);
//序列化
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“Test.out”));
System.out.println(“Saving objects:”);
o.writeObject(t1);\
o.writeObject(t2);
o.close();
//反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream(“Test.out”));
System.out.println(“Recovering objects:”);
t1 = (Test)in.readObject();
System.out.println(t1);
t2 = (Test)in.readObject();
System.out.println(t2);
}
}
输出结果:
Constructing objects:
Test(String x, int a)
A String 47
Test Constructor
null0
Saving objects:
Test.writeExternal
Test.writeExternal
Recovering objects:
Test Constructor
Test.readExternal
A String 47
Test Constructor
Test.readExternal
null0
该例子中,当创建对象使用非无参数构造方法时,对象字段被初始化,因此序列化时可以将初始化的值保存。当创建对象使用无参数的构造方法时,对象的字段没有被赋值而使用默认的初始化值。反序列化时只会调用默认的无参数构造方法。
因此,为了使序列化和反序列化更高效使用,在序列化时,调用writeExternal()只写有用的重要数据,而在反序列化时,readObject()只读取有用的重要数据。
4.transient关键字:
当对象实现Serializable接口进行自动序列化时,类中某些字段不想被序列化,需要使用transient关键字,虽然Externalizable通过writeExternal()方法也可以实现此功能,但是序列化不是自动进行的,使用Serializable和transient关键字更加方便。
例子如下:
[java] view
plaincopy
import java.io.*;
public class User implements Serializable{
private String username;
private transient String password;
public User(String name, String pwd){
username = name;
password = pwd;
}
public String toString(){
return “username:” + username + “, password:” + password;
}
public static void main(String[] args)throws Exception{
User user = new User(“Test”, “passwd”);
System.out.println(“User=” + user);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“User.out”));
o.writeObject(user);
o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(“User.out”));
System.out.println(“Recovering object:”);
user = (User)in.readObject();
System.out.println(“User=” + user);
}
}
输出结果:
User=username:Test,password:passwd
Recovering object:
User=username:Test,password:null
注意:由于Externalizable默认序列化不存储任何字段,所以transient关键字只在Serializable中使用。
1.简单的序列化和反序列化:
最简单的序列化是对象实现Serializable序列化接口,这个接口是一个标记接口,不需要实现任何方法。
下面的小例子简单展示java对象序列化和反序列化的过程:
[java] view
plaincopy
import java.io.*;
//简单的测试对象
public class TestObject implements Serializable{}
import java.io.*;
//序列化
public class SerializeObject{
public static void main(String[] args)throws Exception{
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(“x.file”));
TestObject obj = new TestObject();
//将TestObject对象序列化到x.file文件中
out.write(obj);
}
}
import java.io.*;
//反序列化
public class DeserializeObject{
public static void main(String[] args)throw Exception{
ObjectInputStream in = new ObjectInputStream(new FileInputStream(“x.file”));
Object myObj = in.readObject();
System.out.println(myObj.getClass());
}
}
输出结果:
class TestObject
在序列化时,使用ObjectOutputStream将对象序列化写出,反序列化时,使用ObjectInputStream将对象反序列化读入。
注意:反序列化对象使用时,对象的class文件必须在classpath中,否则,JVM找不到对象的class文件会抛出ClassNotFoundException。
2.序列化控制:
默认的Serializable序列化是将对象整体序列化,但是对于一些特殊的需求例如:序列化部分对象或者反序列化部分对象的情况,就必须使用Externalizable接口来代替Serializable接口,Externalizable的writeExternal()和readExternal()方法可以实现对序列化的控制,这两个方法在对象序列化和反序列化时自动调用,例子如下:
[java] view
plaincopy
import java.io.*;
class Blip1 implements Externalizable{
public Blip1(){
System.out.println(“Blip1 Constructor”);
}
public void writeExternal(ObjectOutput out)throws IOException{
System.out.println(“Blip1.writeExternal”);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
System.out.println(Blip1.readExternal);
}
}
class Blip2 implements Externalizable{
Blip1(){
System.out.println(“Blip2 Constructor”);
}
public void writeExternal(ObjectOutput out)throws IOException{
System.out.println(“Blip2.writeExternal”);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException{
System.out.println(Blip2.readExternal);
}
}
public class Blips{
public static void main(String[] args)throws IOException, ClassNotFoundException{
System.out.println(“Constructing objects:”);
Blip1 b1 = new Blip1();
Blip2 b2 = new Blip2();
//序列化
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“Blips.out”));
System.out.println(“Saving objects:”);
o.writeObject(b1);
o.writeObject(b2);
//反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream(“Blips.out”));
System.out.println(“Recovering b1:”);
b1 = (Blip1)in.readObject();
//由于Blip2的默认无参数构造方法不是public的,所以会抛异常
//System.out.println(“Recovering b2:”);
//b2 = (Blip2)in.readObject();
}
}
输出结果:
Constructing objects:
Blip1 Constructor
Blip2 Constructor
Saving objects:
Blip1.writeExternal
Blip2.writeExternal
Recovering b1:
Blip1 Constructor
Blip1.readExternal
注意:由于对象在反序列化时需要调用默认的public的无参数构造方法创建对象,所以Blip2非public类型无参数构造方法无法反序列化。所以使用Externalizable序列化和反序列化时,对象必须要有public类型的无参数构造方法,这一点是Externalizable和Serializable的区别。
Serializable和Externlizable反序列化的区别:
(1).Serializable的反序列化是通过序列化的字节数组序列进行反序列化的。对象的序列化的反序列化都是自动进行的。
(2).Externalizable的反序列化是通过调用默认的构造方法进行的。对象的序列化需要使用writeExternal()显式控制,对象的反序列化需要使用readExternal()显式控制,不是自动进行的。
3. Externlizable序列化高级:
使用Externlizable序列化和反序列化对象时,readExternal()和writeExternal()方法可以对象中指定字段进行初始化,例子如下:
[java] view
plaincopy
import java.io.*;
public class Test implements Externalizable{
private int i;
private String s;
public Test(){
System.out.println(“Test Constructor”);
}
public Test(String x, int a){
System.out.println(“Test(String x, int a)”);
i = a;
s = x;
}
public void toString(){
return s + i;
}
public void writeExternal(ObjectOutput out)throws IOException{
System.out.println(“Test.writeExternal”);
out.writeObject(s);
out.writeInt(i);
}
public void readExternal(ObjectInput in)throws IOException, ClassNotFoundException{
System.out.println(“Test.readExternal”);
s = (String)in.readObject();
i = in.readInt();
}
public static void main()throws IOException, ClassNotFoundException{
System.out.println(“Constructing objects:”);
Test t1 = new Test(“A String”, 47);
Test t2 = new Test();
System.out.println(t1);
System.out.println(t2);
//序列化
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“Test.out”));
System.out.println(“Saving objects:”);
o.writeObject(t1);\
o.writeObject(t2);
o.close();
//反序列化
ObjectInputStream in = new ObjectInputStream(new FileInputStream(“Test.out”));
System.out.println(“Recovering objects:”);
t1 = (Test)in.readObject();
System.out.println(t1);
t2 = (Test)in.readObject();
System.out.println(t2);
}
}
输出结果:
Constructing objects:
Test(String x, int a)
A String 47
Test Constructor
null0
Saving objects:
Test.writeExternal
Test.writeExternal
Recovering objects:
Test Constructor
Test.readExternal
A String 47
Test Constructor
Test.readExternal
null0
该例子中,当创建对象使用非无参数构造方法时,对象字段被初始化,因此序列化时可以将初始化的值保存。当创建对象使用无参数的构造方法时,对象的字段没有被赋值而使用默认的初始化值。反序列化时只会调用默认的无参数构造方法。
因此,为了使序列化和反序列化更高效使用,在序列化时,调用writeExternal()只写有用的重要数据,而在反序列化时,readObject()只读取有用的重要数据。
4.transient关键字:
当对象实现Serializable接口进行自动序列化时,类中某些字段不想被序列化,需要使用transient关键字,虽然Externalizable通过writeExternal()方法也可以实现此功能,但是序列化不是自动进行的,使用Serializable和transient关键字更加方便。
例子如下:
[java] view
plaincopy
import java.io.*;
public class User implements Serializable{
private String username;
private transient String password;
public User(String name, String pwd){
username = name;
password = pwd;
}
public String toString(){
return “username:” + username + “, password:” + password;
}
public static void main(String[] args)throws Exception{
User user = new User(“Test”, “passwd”);
System.out.println(“User=” + user);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(“User.out”));
o.writeObject(user);
o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(“User.out”));
System.out.println(“Recovering object:”);
user = (User)in.readObject();
System.out.println(“User=” + user);
}
}
输出结果:
User=username:Test,password:passwd
Recovering object:
User=username:Test,password:null
注意:由于Externalizable默认序列化不存储任何字段,所以transient关键字只在Serializable中使用。
相关文章推荐
- 《Java编程思想》学习笔记16——枚举
- 《Java编程思想》学习笔记14——I/O高级
- 《Java编程思想》学习笔记13——Java new I/O(二)
- eclipse最佳设置
- 《Java编程思想》学习笔记12——Java new I/O(一)
- 《Java编程思想》学习笔记11——Java I/O
- eclipse设置文件默认打开方式
- 《Java编程思想》学习笔记10——文件和目录常用操作
- Java RMI之HelloWorld篇
- Java学习 - Thread的Stop方法以及替换实现
- 《Java编程思想》学习笔记8——泛型编程高级
- 《Java编程思想》学习笔记9——集合容器高级
- 《Java编程思想》学习笔记6——Java动态代理
- 《Java编程思想》学习笔记7——泛型编程基础
- eclipse git提交代码
- java.lang.OutOfMemoryError: Java heap space
- java基础(八)---map
- maven+spring+springMVC+mybatis环境搭建
- Fix for Cannot recover key error in JAVA
- 《Java编程思想》学习笔记5——正则表达式量词匹配