Java 对象序列化与反序列化知识点汇总
2013-08-20 19:28
429 查看
转自: http://lapulande.iteye.com/blog/721633
一、两个概念,何为序列化?何为反序列化?
序列化:将对象转化成流的过程称为序列化。
反序列化:将流转化成对象的过程称之为反序列化。
二、序列化机制一般用途?
1.需要将对象的状态保存到文件中,而后能够通过读入对象状态来重新构造对象,恢复程序状态
2.使用套接字在网络上传送对象的程序来说,是很有用的。
3.通过序列化在进程间传递对象。
三、Java对象序列化究竟保存的是什么?
Java的序列化机制只序列化对象的属性值,而不会去序列化什么所谓的方法。其实这个问题简单思考一下就可以搞清楚,方法是不带状态的,就是一些指令,指令是不需要序列化的,只要你的JVM classloader可以load到这个类,那么类方法指令自然就可以获得。序列化真正需要保存的只是:对象的类型,对象属性的类型,对象属性的值。
四、序列化和反序列化的操作
a) Java对象和java.io.Serializable接口
在java中要想使一个java对象可以实现序列化与反序列化,必须让该类实现java.io.Serializable接口,它并未指定要实现的方法,所以Serializable被称为"tagging interface" ,但是它仅仅"tags"它自己的对象是一个特殊的类型。任一个您希望serialize的对象都应该实现这个接口。这是必须的。否则,用到流技术时将根本不工作。例如,如果您试着去serialize 一个没有实现这个接口的对象,一个 NotSerializableException将产生。 类通过实现
java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
java.io.Serializable接口定义如下:
public interface Serializable {
}
b) 序列化和反序列化
序列化主要依赖java.io.ObjectOutputStream类,该类对java.io.FileOutputStream进一步做了封装,这里主要使用ObjectOutputStream类的writeObject()方法实现序列化功能。
反序列化主要依赖java.io.ObjectInputStream类,这里主要使用ObjectInputStream类的readObject()方法实现序列化功能。
在序列化的时候,writeObject与 readObject之间的先后顺序。readObject将最先write的object read出来。用数据结构的术语来讲就姑且称之为先进先出吧!
在序列化时,有几点要注意的:
1:当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
2:如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
3:如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
还有我们对某个对象进行序列化时候,往往对整个对象全部序列化了,比如说对象里有些数据不希望序列化,一个方法可以用transient来标识,另一个方法我们可以在这个类里重写二个方法
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException
Java代码
class ObjectSerialTest
{
public static void main(String[] args) throws Exception
{
Employee e1 = new Employee( " zhangsan " , 25 , 3000.50 );
Employee e2 = new Employee( " lisi " , 24 , 3200.40 );
Employee e3 = new Employee( " wangwu " , 27 , 3800.55 );
FileOutputStream fos = new FileOutputStream( " employee.txt " );
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(e1);
oos.writeObject(e2);
oos.writeObject(e3);
oos.close();
FileInputStream fis = new FileInputStream( " employee.txt " );
ObjectInputStream ois = new ObjectInputStream(fis);
Employee e;
for ( int i = 0 ;i < 3 ;i ++ )
{
e = (Employee)ois.readObject();
System.out.println(e.name + " : " + e.age + " : " + e.salary);
}
ois.close();
}
}
class Employee implements Serializable
{
String name;
int age;
double salary;
transient Thread t = new Thread();
public Employee(String name, int age, double salary)
{
this .name = name;
this .age = age;
this .salary = salary;
}
private void writeObject(java.io.ObjectOutputStream oos) throws IOException
{
oos.writeInt(age);
oos.writeUTF(name);
System.out.println( " Write Object " );
}
private void readObject(java.io.ObjectInputStream ois) throws IOException
{
age = ois.readInt();
name = ois.readUTF();
System.out.println( " Read Object " );
}
}
其实还有一个接口java.io.Externalizable,它继承了Serializable接口,所以也可以通过实现它,定义readExternal和writeExternal方法来实现序列化。
ObjectOutputStream调用类的writeExternal方法对Customer对象的非transient实例变量进行序列化;
ObjectInputStream首先通过类的无参数构造函数实例化一个对象,再用readExternal方法对对象的非transient实例变量进行反序列化。
五、总结
如果采用默认的序列化方式,只要让一个类实现Serializable接口,其实例就可以被序列化。通常,专门为继承而设计的类应该尽量不要实现 Serializable接口,因为一旦父类实现了Serializable接口,其所有子类也都是可序列化的了。
默认的序列化方式的不足之处:
1.直接对对象的不宜对外公开的敏感数据进行序列化,这是不安全的;
2.不会检查对象的成员变量是否符合正确的约束条件,有可能被传改数据而导致运行异常;
3.需要对对象图做递归遍历,如果对象图很复杂,会消耗很多资源,设置引起Java虚拟机的堆栈溢出;
4.使类的接口被类的内部实现约束,制约类的升级与维护。
通过实现Serializable接口的private类型的writeObject()和readObject(),或是实现 Externalizable接口,并实现writeExternal()与readExternal()方法,并提供public类型的无参数构造函数两种方式来控制序列化过程可以有效规避默认序列化方式的不足之处。
一、两个概念,何为序列化?何为反序列化?
序列化:将对象转化成流的过程称为序列化。
反序列化:将流转化成对象的过程称之为反序列化。
二、序列化机制一般用途?
1.需要将对象的状态保存到文件中,而后能够通过读入对象状态来重新构造对象,恢复程序状态
2.使用套接字在网络上传送对象的程序来说,是很有用的。
3.通过序列化在进程间传递对象。
三、Java对象序列化究竟保存的是什么?
Java的序列化机制只序列化对象的属性值,而不会去序列化什么所谓的方法。其实这个问题简单思考一下就可以搞清楚,方法是不带状态的,就是一些指令,指令是不需要序列化的,只要你的JVM classloader可以load到这个类,那么类方法指令自然就可以获得。序列化真正需要保存的只是:对象的类型,对象属性的类型,对象属性的值。
四、序列化和反序列化的操作
a) Java对象和java.io.Serializable接口
在java中要想使一个java对象可以实现序列化与反序列化,必须让该类实现java.io.Serializable接口,它并未指定要实现的方法,所以Serializable被称为"tagging interface" ,但是它仅仅"tags"它自己的对象是一个特殊的类型。任一个您希望serialize的对象都应该实现这个接口。这是必须的。否则,用到流技术时将根本不工作。例如,如果您试着去serialize 一个没有实现这个接口的对象,一个 NotSerializableException将产生。 类通过实现
java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
java.io.Serializable接口定义如下:
public interface Serializable {
}
b) 序列化和反序列化
序列化主要依赖java.io.ObjectOutputStream类,该类对java.io.FileOutputStream进一步做了封装,这里主要使用ObjectOutputStream类的writeObject()方法实现序列化功能。
反序列化主要依赖java.io.ObjectInputStream类,这里主要使用ObjectInputStream类的readObject()方法实现序列化功能。
在序列化的时候,writeObject与 readObject之间的先后顺序。readObject将最先write的object read出来。用数据结构的术语来讲就姑且称之为先进先出吧!
在序列化时,有几点要注意的:
1:当一个对象被序列化时,只保存对象的非静态成员变量,不能保存任何的成员方法和静态的成员变量。
2:如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被保存。
3:如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
还有我们对某个对象进行序列化时候,往往对整个对象全部序列化了,比如说对象里有些数据不希望序列化,一个方法可以用transient来标识,另一个方法我们可以在这个类里重写二个方法
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException;
private void writeObject(java.io.ObjectOutputStream stream)
throws IOException
Java代码
class ObjectSerialTest
{
public static void main(String[] args) throws Exception
{
Employee e1 = new Employee( " zhangsan " , 25 , 3000.50 );
Employee e2 = new Employee( " lisi " , 24 , 3200.40 );
Employee e3 = new Employee( " wangwu " , 27 , 3800.55 );
FileOutputStream fos = new FileOutputStream( " employee.txt " );
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(e1);
oos.writeObject(e2);
oos.writeObject(e3);
oos.close();
FileInputStream fis = new FileInputStream( " employee.txt " );
ObjectInputStream ois = new ObjectInputStream(fis);
Employee e;
for ( int i = 0 ;i < 3 ;i ++ )
{
e = (Employee)ois.readObject();
System.out.println(e.name + " : " + e.age + " : " + e.salary);
}
ois.close();
}
}
class Employee implements Serializable
{
String name;
int age;
double salary;
transient Thread t = new Thread();
public Employee(String name, int age, double salary)
{
this .name = name;
this .age = age;
this .salary = salary;
}
private void writeObject(java.io.ObjectOutputStream oos) throws IOException
{
oos.writeInt(age);
oos.writeUTF(name);
System.out.println( " Write Object " );
}
private void readObject(java.io.ObjectInputStream ois) throws IOException
{
age = ois.readInt();
name = ois.readUTF();
System.out.println( " Read Object " );
}
}
class ObjectSerialTest { public static void main(String[] args) throws Exception { Employee e1 = new Employee( " zhangsan " , 25 , 3000.50 ); Employee e2 = new Employee( " lisi " , 24 , 3200.40 ); Employee e3 = new Employee( " wangwu " , 27 , 3800.55 ); FileOutputStream fos = new FileOutputStream( " employee.txt " ); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(e1); oos.writeObject(e2); oos.writeObject(e3); oos.close(); FileInputStream fis = new FileInputStream( " employee.txt " ); ObjectInputStream ois = new ObjectInputStream(fis); Employee e; for ( int i = 0 ;i < 3 ;i ++ ) { e = (Employee)ois.readObject(); System.out.println(e.name + " : " + e.age + " : " + e.salary); } ois.close(); } } class Employee implements Serializable { String name; int age; double salary; transient Thread t = new Thread(); public Employee(String name, int age, double salary) { this .name = name; this .age = age; this .salary = salary; } private void writeObject(java.io.ObjectOutputStream oos) throws IOException { oos.writeInt(age); oos.writeUTF(name); System.out.println( " Write Object " ); } private void readObject(java.io.ObjectInputStream ois) throws IOException { age = ois.readInt(); name = ois.readUTF(); System.out.println( " Read Object " ); } }
其实还有一个接口java.io.Externalizable,它继承了Serializable接口,所以也可以通过实现它,定义readExternal和writeExternal方法来实现序列化。
ObjectOutputStream调用类的writeExternal方法对Customer对象的非transient实例变量进行序列化;
ObjectInputStream首先通过类的无参数构造函数实例化一个对象,再用readExternal方法对对象的非transient实例变量进行反序列化。
五、总结
如果采用默认的序列化方式,只要让一个类实现Serializable接口,其实例就可以被序列化。通常,专门为继承而设计的类应该尽量不要实现 Serializable接口,因为一旦父类实现了Serializable接口,其所有子类也都是可序列化的了。
默认的序列化方式的不足之处:
1.直接对对象的不宜对外公开的敏感数据进行序列化,这是不安全的;
2.不会检查对象的成员变量是否符合正确的约束条件,有可能被传改数据而导致运行异常;
3.需要对对象图做递归遍历,如果对象图很复杂,会消耗很多资源,设置引起Java虚拟机的堆栈溢出;
4.使类的接口被类的内部实现约束,制约类的升级与维护。
通过实现Serializable接口的private类型的writeObject()和readObject(),或是实现 Externalizable接口,并实现writeExternal()与readExternal()方法,并提供public类型的无参数构造函数两种方式来控制序列化过程可以有效规避默认序列化方式的不足之处。
相关文章推荐
- Thinking in java 琐碎知识点之 I/O流 、对象序列化
- java知识点汇总之十二面向对象
- Java知识点整理:第十三章:字符串的序列化(文字的编码方案)、字符流(Reader Writer)、对象序列化
- 【Java】IO操作之对象序列化及反序列化
- 阿里___Java对象的序列化
- 理解Java对象序列化
- Java序列化对象的存储和读取
- 4.java基础之面向对象知识点总结
- Java面向对象知识点20个
- Java基础学习总结——Java对象的序列化和反序列化
- Java 序列化对象存储
- Java对象的序列化和反序列化
- Java 对象序列化
- Java的IO流与对象的序列化浅谈
- Java 知识点:序列化
- Java 中对象的序列化技术(zz一篇java序列化的好文,强烈推荐)
- java--对象自定义序列化简单应用,用于性能的优化
- Java基础回顾 : 对象序列化和反序列化
- python的io 与java的io流的使用及对象的序列化
- Java对象序列化