serialized接口是标记接口,在jvm中是如何执行他的
来源:互联网 发布:json 值里面有双引号 编辑:程序博客网 时间:2024/05/29 16:24
大家都知道Serializable是一个mark interface,告诉JVM这个对象可以被转换成二进制流来传输.
但是Serializable与Externalizable的转换二进制流的过程是不一样的.
Serializable 在我们实现这个接口的时候,我们可以使用4个私有方法来控制序列化的过程:
我们来看一个例子:
- public class FooImpl implements java.io.Serializable{
- private String message;
- public String getFoo() {
- return message;
- }
- public void setMessage(String message) {
- this.message = message;
- }
- private void writeObject(java.io.ObjectOutputStream out) throws IOException {
- System.out.println("writeObject invoked");
- out.writeObject(this.message == null ? "hohohahaha" : this.message);
- }
- private void readObject(java.io.ObjectInputStream in) throws IOException,
- ClassNotFoundException {
- System.out.println("readObject invoked");
- this.message = (String) in.readObject();
- System.out.println("got message:" + message);
- }
- private Object writeReplace() throws ObjectStreamException {
- System.out.println("writeReplace invoked");
- return this;
- }
- private Object readResolve() throws ObjectStreamException {
- System.out.println("readResolve invoked");
- return this;
- }
- public Object serialize() throws IOException, ClassNotFoundException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(this);
- ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
- ObjectInputStream ois = new ObjectInputStream(bais);
- return ois.readObject();
- }
- public static void main(String[] args) throws IOException,
- ClassNotFoundException {
- FooImpl fooimpl = new FooImpl();
- fooimpl.serialize();
- }
我们运行这段代码看到的debug信息:
writeReplace invoked
writeObject invoked
readObject invoked
readResolve invoked
当进行序列化的时候:
首先JVM会先调用writeReplace方法,在这个阶段,我们可以进行张冠李戴,将需要进行序列化的对象换成我们指定的对象.
跟着JVM将调用writeObject方法,来将对象中的属性一个个进行序列化,我们可以在这个方法中控制住哪些属性需要序列化.
当反序列化的时候:
JVM会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,反序列化回来.
然后在readResolve方法中,我们也可以指定JVM返回我们特定的对象(不是刚刚序列化回来的对象).
注意到在writeReplace和readResolve,我们可以严格控制singleton的对象,在同一个JVM中完完全全只有唯一的对象,控制不让singleton对象产生副本.
Externalizable 是一个有实际方法需要实现的interface,包括writeExternal和readExternal:
- public class FooImpl implements java.io.Externalizable {
- private String message;
- public String getFoo() {
- return message;
- }
- public void setMessage(String message) {
- this.message = message;
- }
- private Object writeReplace() throws ObjectStreamException {
- System.out.println("writeReplace invoked");
- return this;
- }
- private Object readResolve() throws ObjectStreamException {
- System.out.println("readResolve invoked");
- return this;
- }
- public Object serialize() throws IOException, ClassNotFoundException {
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
- ObjectOutputStream oos = new ObjectOutputStream(baos);
- oos.writeObject(this);
- ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
- ObjectInputStream ois = new ObjectInputStream(bais);
- return ois.readObject();
- }
- public void readExternal(ObjectInput arg0) throws IOException,
- ClassNotFoundException {
- System.out.println("readExternal invoked");
- Object obj = arg0.readObject();
- }
- public void writeExternal(ObjectOutput arg0) throws IOException {
- System.out.println("writeExternal invoked");
- arg0.writeObject("Hello world");
- }
- public static void main(String[] args) throws IOException,
- ClassNotFoundException {
- FooImpl fooimpl = new FooImpl();
- fooimpl.serialize();
- }
- }
我们运行这段代码看到的debug信息:
writeReplace invoked
writeExternal invoked
readExternal invoked
readResolve invoked
在此writeExternal 和readExternal 的作用与writeObject和readObject 一样.
最后,当我们同时实现了两个interface的时候,JVM只运行Externalizable 接口里面的writeExternal 和readExternal 方法对序列化内容进行处理.
需要注意的是:Serializable是一个真正的mark interface,
writeObject,readObject, writeReplace,readResolve是直接与JVM通信,告诉JVM序列化的内容.
1.关键字transient
当一个成员被声明为transient时,在对象被保存的时候,该成员将不被保存。
2. 通过实现了Externalizable接口来产生Serialize功能
1) 在保存对象时不会保存任何成员对象。但我们可以手工保存成员对象(下面将讲到)。
2) Default构造函数必须为public。因为在次第读取对象时,会调用default构造函数。因为对象中的成员对象不一定会被保存,所以要通过构造函数来进行初始化。
3) Extrenalizable接口有writeExternal(ObjectOutput)和readExternal(ObjectInput)两个函数。在对实现了Externalizable接口的类进行次第读写时,会调用这两个函数。但是在恢复对象时,是先调用default构造函数再调用readExternal()函数的。
3. Externalizable接口和Serializable接口的区别
1) 通过实现Serializable接口的方法,在保存对象时会把对象中所包含的成员对象也保存下来;而通过实现Externalizable接口的方法,在保存对象时不会保存任何成员对象。
2) 通过实现Serializable接口的方法,在恢复对象时不会调用任何构造函数(包括default构造函数);而通过实现Externalizable接口的方法,在恢复对象时会调用default构造函数。然后再调用readExternal()函数。
3) 利用writeExternal()和readExternal()函数来控制成员对象
4. Java的怪异之处
1) 在下面的代码中我们可以看到,Blip3只实现了Serializable接口,而该接口只是个标志接口,所以这两个函数并不是接口的一部分。
2) 这两个函数被声明为private,按理只能在它们所在的类中被调用,但事实却是它们能被ObjectOutputStream和ObjectInputStream对象的writeObject()和readObject()函数调用。
3) 当调用ObjectOutputStream.writeObject(Object)时,传入的Serializable对象会被检查是否实现自己的writeObject(ObjectOutputStream)。如果有,就会执行扩增的writeObject(ObjectOutputStream)函数。当调用ObjectInputStream.readObject()时的工作过程也一样。
4) 在扩增的writeObject(ObjectOutputStream)中我们可以通过调用defaultWriteobject()函数来执行缺省的writeObject();在扩增的readObject(ObjectInputStream)函数中,我们可以通过调用defaultReadObject()函数来执行缺省的readObject()。在相应的缺省函数中都只对non-transient成员对象进行操作。
5. 关于Serialize的扩充话题
1) 当多个对象被保存到同一个Stream时,如果这些对象的成员对象中有指向相同的第三对象的reference,那么在恢复时也将指向同一个对象。但不相同的两个Stream中的对象的则不同。
- serialized接口是标记接口,在jvm中是如何执行他的
- ns3中loopback接口是在什么时候创建的?
- Tomcat 是如何实现ServletConfig接口的
- SQL语句在数据库中是如何执行的
- 代码是如何在栈中执行
- ServletContext接口是servlet中最大的一个接口
- JVM中helloWorld是如何运行的
- 抽象类和接口的区别是什么?在使用上是如何选择的?
- 接口,接口是更加抽象的
- 当对象类型是一个接口的时候,在Eclipse中如果跳转到该接口对应的实现类
- 接口是AS出来的
- 接口是AS出来的
- 接口是AS出来的
- (转帖)C#中的接口是如何工作的
- GenericServlet抽象类是如何实现ServletConfig接口的
- java后端发布的接口数据是如何加密传输
- OTG接口设备主从功能是如何实现的
- Entry接口是Map接口的内部接口
- 如何学习CMMI
- Hibernate学习30 -- Hibernate查询语言(HQL)4 -- 条件查询
- 在CMMI推广过程中EPG常犯的错误
- OpenSocial后感
- 过程改进方法重于CMMI模型
- serialized接口是标记接口,在jvm中是如何执行他的
- 不要这样做CMMI
- CMMI成功的根本原因是什么?
- JIL
- jquery.validate.js API
- Hibernate学习31 -- Hibernate查询语言(HQL)5 -- 直接使用sql进行查询
- CMMI:收获的欣慰
- 简洁、明晰!数据库设计三大范式应用实例剖析
- 过程改进:宽度优先还是深度优先?