java序列化与反序列化(2)------jdk原生序列化机制Serializable
2017-10-03 21:13
316 查看
使用jdk原生的序列化机制,我们要把需要序列化的类实现Serializable接口或者Externalizable(关于Externalizable这个接口稍后我会讲到),我们这里先说Serializable,Serializable这是一个标记接口没有声明任何的方法。
(1)序列化的基本操作
下面我们构造一个Book类并实现Serializable接口,代码如下:
我们之前说过序列化是保存对象的状态,所以类中的静态变量属于类而不属于对象的状态,所以静态变量是不被序列化的。如果我们有一些不想被序列化的属性,比如程序打开的文件句柄之类的,那么我们可以在这样的域上用transient关键字进行声明。
序列化和反序列化的测试代码如下所示:
测试代码输出结果如下:
begin to execute
create a file: D:\yujie_serialize\yujie_serialize_book1.txt
file D:\yujie_serialize\yujie_serialize_book1.txt already exists
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[], rentTimes=0]
end
(2)自定义序列化方法
在上面我们说过使用transient关键字修饰的域不会被序列化,反序列化时这个域值为类型的默认值,但是如果我们就是希望将transient关键字修饰的域进行序列化,其实我们可以在需要序列化的类中自定义writeObject(ObjectOutputStream out)和readObject(ObjectInputStream in)函数,之后java序列化机制会调用这里定义的这两个函数进行序列化。
我们在Book类中增加如下代码:
private void writeObject(ObjectOutputStream out) throws IOException {
//调用默认的序列化机制 这里会正常的序列化对象的非transient修饰的域值
out.defaultWriteObject();
//调用out写入transient修饰的rentTimes域
out.writeInt(rentTimes);
System.out.println("invoke writeObject");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
//调用默认的反序列化机制 这里会正常的反序列化对象的非transient修饰的域值
in.defaultReadObject();
//调用ObjectInputStream读入我们序列化时写入的rentTimes字段
rentTimes = in.readInt();
System.out.println("invoke readObject");
}测试输出结果:
begin to execute
create a file: D:\yujie_serialize\yujie_serialize_book1.txt
invoke writeObject
file D:\yujie_serialize\yujie_serialize_book1.txt already exists
invoke readObject
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[], rentTimes=15]
end
我们看到通过自定义函数写入的rentTimes域值,反序列化之后成功读取结果15。
(3)父子继承关系的序列化
如果父类实现了Serializable接口,子类没有实现Serializable接口,那么子类可以正常序列化。
如果子类实现了Serializable接口,而父类没有实现Serializable接口,那么必须满足如下条件子类才能正常序列化,
第一:父类必须提供一个公共的无参默认构造函数
第二:子类负责序列化父类的对象状态
我们继续改造上面的代码,接下类我们定义一个父类Paper并且实现Serializable接口代码如下:
/**
* 父类实现Serializable接口,子类直接继承父类
* 子类可直接序列化
* @author yujie.wang
*
*/
public class Paper implements Serializable{
private int length;
private int width;
public Paper(int length, int width) {
this.length = length;
this.width = width;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
子类Book取消实现Serializable接口,直接继承Paper父类,然后运行序列化测试代码,程序正常输出如下:
begin to execute
create a file: D:\yujie_serialize\yujie_serialize_book1.txt
invoke writeObject
file D:\yujie_serialize\yujie_serialize_book1.txt already exists
invoke readObject
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[], rentTimes=15]
end
第二种情况
父类代码改造如下:
/**
* 父类没有实现接口Seria
cf0d
lizable,父类和子类必须满足一定的条件才能正常序列化
* 子类可直接序列
* @author yujie.wang
*
*/
public class Paper{
private int length;
private int width;
//父类没有实现Serializable接口的情况下
//如果子类希望能正常序列化,则父类必须提供一个默认的无参构造函数
public Paper(){
}
public Paper(int length, int width) {
this.length = length;
this.width = width;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
子类Book改造如下:
/**
* 序列化类的模型继承未实现Serializable接口的父类
* @author yujie.wang
* @since 10/03/2017
*/
public class Book extends Paper implements Serializable {
//序列化的版本号
private static final long serialVersionUID = 6165984730624879548L;
private String name;
private double price;
private boolean status;
private int rent_days;
private List<String> list;
// transient关键字修饰的域不被序列化
private transient int rentTimes;
// 静态域属于类,不是对象的状态
private static String note = "this is a nice book";
public Book(String name, double price, boolean status, int rent_days, List<String> list,
int rentTimes,int length,int width){
//调用父类的构造函数
super(length, width);
this.name = name;
this.price = price;
this.status = status;
this.rent_days = rent_days;
this.list = list;
this.rentTimes = rentTimes;
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeInt(rentTimes);
//序列化父类的域
out.writeInt(getLength());
out.writeInt(getWidth());
System.out.println("invoke writeObject");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
rentTimes = in.readInt();
//反序列化父类的域
setLength( in.readInt());
setWidth(in.readInt());
System.out.println("invoke readObject");
}
public static String getNote() {
return note;
}
public static void setNote(String note) {
Book.note = note;
}
public int getRentTimes() {
return rentTimes;
}
public void setRentTimes(int rentTimes) {
this.rentTimes = rentTimes;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public int getRent_days() {
return rent_days;
}
public void setRent_days(int rent_days) {
this.rent_days = rent_days;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
// 重写toString方法 输出父类的域
@Override
public String toString() {
return "Book [name=" + name + ", price=" + price + ", status=" + status
+ ", rent_days=" + rent_days + ", list=" + list
+ ", rentTimes=" + rentTimes + "length"+ getLength() + "width: "+ getWidth() + "]";
}
}
测试代码中Book的构造函数传入父类的域,运行测试代码输出:
begin to execute
create a file: D:\yujie_serialize\yujie_serialize_book1.txt
invoke writeObject
file D:\yujie_serialize\yujie_serialize_book1.txt already exists
invoke readObject
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[], rentTimes=15length20width: 29]
end
当然如果父类没有提供无参的公共构造函数,运行序列化测试代码将报如下异常:
Exception in thread "main" java.io.InvalidClassException: com.yujie.seria.Book; com.yujie.seria.Book; no valid constructor
at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at com.yujie.seria.Serialize_Main.deSerializeObject(Serialize_Main.java:50)
at com.yujie.seria.Serialize_Main.main(Serialize_Main.java:34)
public abstract interface Serializable { }
(1)序列化的基本操作
下面我们构造一个Book类并实现Serializable接口,代码如下:
/** * 序列化类的模型 * @author yujie.wang * @since 10/03/2017 */ public class Book implements Serializable{ //序列化的版本号 private static final long serialVersionUID = 6165984730624879548L; private String name; private double price; private boolean status; private int rent_days; private List<String> list; // transient关键字修饰的域不被序列化 private transient int rentTimes; // 静态域属于类,不是对象的状态 private static String note = "this is a nice book"; public Book(String name, double price, boolean status, int rent_days, List<String> list, int rentTimes){ this.name = name; this.price = price; this.status = status; this.rent_days = rent_days; this.list = list; this.rentTimes = rentTimes; } public int getRentTimes() { return rentTimes; } public void setRentTimes(int rentTimes) { this.rentTimes = rentTimes; } public String getName() { return name; } public void setName(String name) { this.name = name; } public double getPrice() { return price; } public void setPrice(double price) { this.price = price; } public boolean isStatus() { return status; } public void setStatus(boolean status) { this.status = status; } public int getRent_days() { return rent_days; } public void setRent_days(int rent_days) { this.rent_days = rent_days; } public List<String> getList() { return list; } public void setList(List<String> list) { this.list = list; } @Override public String toString() { return "Book [name=" + name + ", price=" + price + ", status=" + status + ", rent_days=" + rent_days + ", list=" + list + ", rentTimes=" + rentTimes + "]"; } }
我们之前说过序列化是保存对象的状态,所以类中的静态变量属于类而不属于对象的状态,所以静态变量是不被序列化的。如果我们有一些不想被序列化的属性,比如程序打开的文件句柄之类的,那么我们可以在这样的域上用transient关键字进行声明。
序列化和反序列化的测试代码如下所示:
/** * java jdk自带序列化工具测试 * @author yujie.wang * @since 10/03/2017 */ public class Serialize_Main { private static FileInputStream fin; private static FileOutputStream fout; private static String prefix_Path = "D:\\yujie_serialize\\yujie_serialize_book"; private static String suffix_file_name = ".txt"; public static void main(String[] args) throws IOException, ClassNotFoundException { // TODO Auto-generated method stub System.out.println("begin to execute"); Book book = new Book("thinking in java", 99.99, true, 10, new ArrayList<String>(),15); String filePathName = getFileFullPathName("1"); //执行序列化 serializeObject(book,filePathName ); //执行反序列化过程 deSerializeObject(filePathName); System.out.println("end"); } /** * 反序列化 * @param fileName * @throws IOException * @throws ClassNotFoundException */ public static void deSerializeObject(String fileName) throws IOException, ClassNotFoundException{ File file = createFile(fileName); if(file == null) return; fin = new FileInputStream(file); ObjectInputStream ois = new ObjectInputStream(fin); Book book = (Book)ois.readObject(); if(book == null) { System.out.println("boo == null"); } else { System.out.println(book.toString()); } } /** * 序列化一个对象 * @param book * @param fileName * @throws IOException */ public static void serializeObject(Book book, String fileName) throws IOException{ File file = createFile(fileName); if(file == null) return; fout = new FileOutputStream(file); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(book); oos.flush(); oos.close(); fout.close(); } /** * 创建一个文件 * @param fileName * @return * @throws IOException */ public static File createFile(String fileName) throws IOException{ if(fileName == null || fileName.isEmpty()) return null; File file = new File(fileName); if(!file.exists()){ file.createNewFile(); System.out.println("create a file: "+ fileName); } else { System.out.println("file "+ fileName + " already exists"); } return file; } /** * 获得一个全路径的文件名 * @param fileName * @return */ public static String getFileFullPathName(String fileName){ return prefix_Path + fileName +suffix_file_name; } }
测试代码输出结果如下:
begin to execute
create a file: D:\yujie_serialize\yujie_serialize_book1.txt
file D:\yujie_serialize\yujie_serialize_book1.txt already exists
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[], rentTimes=0]
end
(2)自定义序列化方法
在上面我们说过使用transient关键字修饰的域不会被序列化,反序列化时这个域值为类型的默认值,但是如果我们就是希望将transient关键字修饰的域进行序列化,其实我们可以在需要序列化的类中自定义writeObject(ObjectOutputStream out)和readObject(ObjectInputStream in)函数,之后java序列化机制会调用这里定义的这两个函数进行序列化。
我们在Book类中增加如下代码:
private void writeObject(ObjectOutputStream out) throws IOException {
//调用默认的序列化机制 这里会正常的序列化对象的非transient修饰的域值
out.defaultWriteObject();
//调用out写入transient修饰的rentTimes域
out.writeInt(rentTimes);
System.out.println("invoke writeObject");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
//调用默认的反序列化机制 这里会正常的反序列化对象的非transient修饰的域值
in.defaultReadObject();
//调用ObjectInputStream读入我们序列化时写入的rentTimes字段
rentTimes = in.readInt();
System.out.println("invoke readObject");
}测试输出结果:
begin to execute
create a file: D:\yujie_serialize\yujie_serialize_book1.txt
invoke writeObject
file D:\yujie_serialize\yujie_serialize_book1.txt already exists
invoke readObject
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[], rentTimes=15]
end
我们看到通过自定义函数写入的rentTimes域值,反序列化之后成功读取结果15。
(3)父子继承关系的序列化
如果父类实现了Serializable接口,子类没有实现Serializable接口,那么子类可以正常序列化。
如果子类实现了Serializable接口,而父类没有实现Serializable接口,那么必须满足如下条件子类才能正常序列化,
第一:父类必须提供一个公共的无参默认构造函数
第二:子类负责序列化父类的对象状态
我们继续改造上面的代码,接下类我们定义一个父类Paper并且实现Serializable接口代码如下:
/**
* 父类实现Serializable接口,子类直接继承父类
* 子类可直接序列化
* @author yujie.wang
*
*/
public class Paper implements Serializable{
private int length;
private int width;
public Paper(int length, int width) {
this.length = length;
this.width = width;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
子类Book取消实现Serializable接口,直接继承Paper父类,然后运行序列化测试代码,程序正常输出如下:
begin to execute
create a file: D:\yujie_serialize\yujie_serialize_book1.txt
invoke writeObject
file D:\yujie_serialize\yujie_serialize_book1.txt already exists
invoke readObject
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[], rentTimes=15]
end
第二种情况
父类代码改造如下:
/**
* 父类没有实现接口Seria
cf0d
lizable,父类和子类必须满足一定的条件才能正常序列化
* 子类可直接序列
* @author yujie.wang
*
*/
public class Paper{
private int length;
private int width;
//父类没有实现Serializable接口的情况下
//如果子类希望能正常序列化,则父类必须提供一个默认的无参构造函数
public Paper(){
}
public Paper(int length, int width) {
this.length = length;
this.width = width;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
}
子类Book改造如下:
/**
* 序列化类的模型继承未实现Serializable接口的父类
* @author yujie.wang
* @since 10/03/2017
*/
public class Book extends Paper implements Serializable {
//序列化的版本号
private static final long serialVersionUID = 6165984730624879548L;
private String name;
private double price;
private boolean status;
private int rent_days;
private List<String> list;
// transient关键字修饰的域不被序列化
private transient int rentTimes;
// 静态域属于类,不是对象的状态
private static String note = "this is a nice book";
public Book(String name, double price, boolean status, int rent_days, List<String> list,
int rentTimes,int length,int width){
//调用父类的构造函数
super(length, width);
this.name = name;
this.price = price;
this.status = status;
this.rent_days = rent_days;
this.list = list;
this.rentTimes = rentTimes;
}
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
out.writeInt(rentTimes);
//序列化父类的域
out.writeInt(getLength());
out.writeInt(getWidth());
System.out.println("invoke writeObject");
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
rentTimes = in.readInt();
//反序列化父类的域
setLength( in.readInt());
setWidth(in.readInt());
System.out.println("invoke readObject");
}
public static String getNote() {
return note;
}
public static void setNote(String note) {
Book.note = note;
}
public int getRentTimes() {
return rentTimes;
}
public void setRentTimes(int rentTimes) {
this.rentTimes = rentTimes;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public int getRent_days() {
return rent_days;
}
public void setRent_days(int rent_days) {
this.rent_days = rent_days;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
// 重写toString方法 输出父类的域
@Override
public String toString() {
return "Book [name=" + name + ", price=" + price + ", status=" + status
+ ", rent_days=" + rent_days + ", list=" + list
+ ", rentTimes=" + rentTimes + "length"+ getLength() + "width: "+ getWidth() + "]";
}
}
测试代码中Book的构造函数传入父类的域,运行测试代码输出:
begin to execute
create a file: D:\yujie_serialize\yujie_serialize_book1.txt
invoke writeObject
file D:\yujie_serialize\yujie_serialize_book1.txt already exists
invoke readObject
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[], rentTimes=15length20width: 29]
end
当然如果父类没有提供无参的公共构造函数,运行序列化测试代码将报如下异常:
Exception in thread "main" java.io.InvalidClassException: com.yujie.seria.Book; com.yujie.seria.Book; no valid constructor
at java.io.ObjectStreamClass.checkDeserialize(Unknown Source)
at java.io.ObjectInputStream.readOrdinaryObject(Unknown Source)
at java.io.ObjectInputStream.readObject0(Unknown Source)
at java.io.ObjectInputStream.readObject(Unknown Source)
at com.yujie.seria.Serialize_Main.deSerializeObject(Serialize_Main.java:50)
at com.yujie.seria.Serialize_Main.main(Serialize_Main.java:34)
相关文章推荐
- java序列化与反序列化(4)------jdk原生序列化机制实现深拷贝
- java序列化与反序列化(3)------jdk原生序列化机制Externalizable
- 深入理解Java的序列化和反序列化机制——Serializable
- Java序列化技术性能分析(JDK原生与Protostuff)
- spring-data-redis 整合,以及使用kryo序列化代替jdk原生序列化机制
- Java序列化技术性能分析(JDK原生与Protostuff)
- Java序列化技术性能分析(JDK原生与Protostuff)
- Java 序列化Serializable具体解释(附具体样例)
- Java序列化机制
- Java序列化机制和原理
- java类库的阅读笔记_jdk1.7.0_40_java.io.Serializable
- Java的序列化机制
- Java序列化的机制和原理
- 面试题:Java中对象序列化接口(Serializable)的意义
- Java 理论与实践: JDK 5.0 中更灵活、更具可伸缩性的锁定机制--转载
- JAVA序列化Serializable
- 对Java Serializable(序列化)的理解和总结
- 对Java Serializable(序列化)的理解和总结
- [java] JDK 的动态代理机制
- java把对象转化成流,和把流转化成对象(包含clone机制+序列化机制)