Java对象序列化(Object Serialization)
2014-10-23 20:34
363 查看
Java1.1中实现了Serializable接口的对象都可被转换成一系列字节,并可完全恢复成原状。Java中的两个特性运用了对象序列化:远程调用方法(RMI),Java Beans
要序列化一个对象(其类已实现Serializable接口),需要创建一些OutputStream对象,将其封装到ObjectOutputStream对象中,调用writeObject()方法即可将序列化的对象发生到OutputStream中,比如文件、String、网络等。当要恢复对象时,只需将InputStream封装到ObjectInputStream对象中,调用readObject()方法即可,当然此时必须上溯造型到原始类型。
1. Serializable接口实例
package com.test;
import java.io.*;
class Data implements Serializable {
private int i;
Data(int x) { i = x; }
public String toString() {
return Integer.toString(i);
}
}
public class Serial implements Serializable {
//Generate random int
private static int r() {
return (int)(Math.random() * 10);
}
private Data[] d = {new Data(r()), new Data(r()), new Data(r())};
private Serial next;
private char c;
Serial(int i, char x) {
System.out.println(" Serial constructor: " + i);
c = x;
if (--i >0)
next = new Serial(i, (char)(x+1));
}
Serial() {
System.out.println("Default constructor");
}
public String toString() {
String s = ":" + c + "(";
for (int i = 0; i < d.length; i++) {
s += d[i].toString();
}
s += ")";
if (next != null)
s += next.toString();
return s;
}
public static void main(String[] args) {
Serial w = new Serial(6, 'e');
System.out.println("w = " + w);
try {
//write the serialized objects to file
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("serial.out"));
out.writeObject("Serial test");
out.writeObject(w);
out.close(); //will also flush output
//read and restore serialized objects from file
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("serial.out"));
String s = (String)in.readObject();
Serial w2 = (Serial)in.readObject();
System.out.println(s + ", w2 = " + w2);
} catch (Exception e) {
e.printStackTrace();
}
try {
//write the serialized objects to memory
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject("Serial test");
out.writeObject(w);
out.flush();
//read and restore from memory
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(bout.toByteArray()));
String s = (String)in.readObject();
Serial w3 = (Serial)in.readObject();
System.out.println(s + ", w3 = " + w3);
} catch (Exception e) {
e.printStackTrace();
}
}
}在读取并恢复Serializable对象的时候不会允许构建器,而且对象序列化没有用到IO系统的Reader和Writer,而是使用Java1.0的InputStream和OutputStream体系。
2. Externalizable接口
实现了Serializable接口的对象序列化时,默认会将类中所有字段包含进去。但是有时涉及安全问题,有些字段我们不想被序列化,这时可使用Externalizable接口控制序列化过程。Externalizable接口扩展了Serializable接口,并添加了两个方法writeExternal()和readExternal()。在序列化和恢复的过程中会自动调用这两个方法,我们可以通过改写他们控制序列化和恢复过程。
实例1,实现Externalizable接口的对象在恢复是会调用类的默认构建器,注意Blip2的默认构建器不是public的,这样会导致调用权限不够而产生异常
package com.test;
import java.io.*;
import java.util.*;
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 {
Blip2() {
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 External {
public static void main(String[] args) {
System.out.println("Constructing objects: ");
Blip1 b1 = new Blip1();
Blip2 b2 = new Blip2();
try {
//write serialzed objects
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("Blips.out"));
System.out.println("Saving objects: ");
out.writeObject(b1);
out.writeObject(b2);
out.close();
//read and restore objects
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("Blips.out"));
System.out.println("Recovering b1:");
b1 = (Blip1)in.readObject();
//following will throw exception
//as Blip2's default constructor is not public
//b2 = (Blip2)in.readObject();
} catch (Exception e) {
e.printStackTrace();
}
}
}
实例2,在readExternal和writeExternal中控制序列化过程
package com.test;
import java.io.*;
import java.util.*;
public class External2 implements Externalizable {
int i;
String s; //not initialize
public External2() {
System.out.println("External2 constructor");
}
public External2(String x, int a) {
System.out.println("External2(String x, int a)");
s = x;
i = a;
}
public String toString() { return s + i; }
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("External2.writeExternal");
//write the fields you want to serialize
//you can only serialize some fields
out.writeObject(s);
out.writeObject(i);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("External2.readExternal");
//Restore the fields that are serialized
s = (String)in.readObject();
i = in.readInt();
}
public static void main(String[] args) {
System.out.println("Constructing objects: ");
External2 e2 = new External2("A string", 42);
System.out.println(e2.toString());
try {
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("external2.out"));
System.out.println("Saving object: ");
out.writeObject(e2);
out.close();
//restore object
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("external2.out"));
System.out.println("Recovering e2:");
e2 = (External2)in.readObject();
System.out.println(e2.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. transient关键字
实现Serializable接口的类序列化时默认所有fields都会被序列化,transient关键字可以关闭fields的序列化。设置成transient的字段不参与序列化,恢复时简单的设置成默认值,如int 0, 对象句柄 null。
4. writeObject()和readObject()方法代替Externalizable
实现Serializable接口,并添加writeObject()和readObject()方法也可以控制序列化过程。但是这两个方法在类中都被定义成private,按理说外部类是不能调用的,这里序列化过程绕过了检查,这种绕过检查的机制我们普通用户是不可能接触到的。。。
private void writeObject(ObjectOutputStream stream) throws IOException;
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException;
实例:
要序列化一个对象(其类已实现Serializable接口),需要创建一些OutputStream对象,将其封装到ObjectOutputStream对象中,调用writeObject()方法即可将序列化的对象发生到OutputStream中,比如文件、String、网络等。当要恢复对象时,只需将InputStream封装到ObjectInputStream对象中,调用readObject()方法即可,当然此时必须上溯造型到原始类型。
1. Serializable接口实例
package com.test;
import java.io.*;
class Data implements Serializable {
private int i;
Data(int x) { i = x; }
public String toString() {
return Integer.toString(i);
}
}
public class Serial implements Serializable {
//Generate random int
private static int r() {
return (int)(Math.random() * 10);
}
private Data[] d = {new Data(r()), new Data(r()), new Data(r())};
private Serial next;
private char c;
Serial(int i, char x) {
System.out.println(" Serial constructor: " + i);
c = x;
if (--i >0)
next = new Serial(i, (char)(x+1));
}
Serial() {
System.out.println("Default constructor");
}
public String toString() {
String s = ":" + c + "(";
for (int i = 0; i < d.length; i++) {
s += d[i].toString();
}
s += ")";
if (next != null)
s += next.toString();
return s;
}
public static void main(String[] args) {
Serial w = new Serial(6, 'e');
System.out.println("w = " + w);
try {
//write the serialized objects to file
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("serial.out"));
out.writeObject("Serial test");
out.writeObject(w);
out.close(); //will also flush output
//read and restore serialized objects from file
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("serial.out"));
String s = (String)in.readObject();
Serial w2 = (Serial)in.readObject();
System.out.println(s + ", w2 = " + w2);
} catch (Exception e) {
e.printStackTrace();
}
try {
//write the serialized objects to memory
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject("Serial test");
out.writeObject(w);
out.flush();
//read and restore from memory
ObjectInputStream in = new ObjectInputStream(
new ByteArrayInputStream(bout.toByteArray()));
String s = (String)in.readObject();
Serial w3 = (Serial)in.readObject();
System.out.println(s + ", w3 = " + w3);
} catch (Exception e) {
e.printStackTrace();
}
}
}在读取并恢复Serializable对象的时候不会允许构建器,而且对象序列化没有用到IO系统的Reader和Writer,而是使用Java1.0的InputStream和OutputStream体系。
2. Externalizable接口
实现了Serializable接口的对象序列化时,默认会将类中所有字段包含进去。但是有时涉及安全问题,有些字段我们不想被序列化,这时可使用Externalizable接口控制序列化过程。Externalizable接口扩展了Serializable接口,并添加了两个方法writeExternal()和readExternal()。在序列化和恢复的过程中会自动调用这两个方法,我们可以通过改写他们控制序列化和恢复过程。
实例1,实现Externalizable接口的对象在恢复是会调用类的默认构建器,注意Blip2的默认构建器不是public的,这样会导致调用权限不够而产生异常
package com.test;
import java.io.*;
import java.util.*;
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 {
Blip2() {
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 External {
public static void main(String[] args) {
System.out.println("Constructing objects: ");
Blip1 b1 = new Blip1();
Blip2 b2 = new Blip2();
try {
//write serialzed objects
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("Blips.out"));
System.out.println("Saving objects: ");
out.writeObject(b1);
out.writeObject(b2);
out.close();
//read and restore objects
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("Blips.out"));
System.out.println("Recovering b1:");
b1 = (Blip1)in.readObject();
//following will throw exception
//as Blip2's default constructor is not public
//b2 = (Blip2)in.readObject();
} catch (Exception e) {
e.printStackTrace();
}
}
}
实例2,在readExternal和writeExternal中控制序列化过程
package com.test;
import java.io.*;
import java.util.*;
public class External2 implements Externalizable {
int i;
String s; //not initialize
public External2() {
System.out.println("External2 constructor");
}
public External2(String x, int a) {
System.out.println("External2(String x, int a)");
s = x;
i = a;
}
public String toString() { return s + i; }
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("External2.writeExternal");
//write the fields you want to serialize
//you can only serialize some fields
out.writeObject(s);
out.writeObject(i);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("External2.readExternal");
//Restore the fields that are serialized
s = (String)in.readObject();
i = in.readInt();
}
public static void main(String[] args) {
System.out.println("Constructing objects: ");
External2 e2 = new External2("A string", 42);
System.out.println(e2.toString());
try {
ObjectOutputStream out = new ObjectOutputStream(
new FileOutputStream("external2.out"));
System.out.println("Saving object: ");
out.writeObject(e2);
out.close();
//restore object
ObjectInputStream in = new ObjectInputStream(
new FileInputStream("external2.out"));
System.out.println("Recovering e2:");
e2 = (External2)in.readObject();
System.out.println(e2.toString());
} catch (Exception e) {
e.printStackTrace();
}
}
}
3. transient关键字
实现Serializable接口的类序列化时默认所有fields都会被序列化,transient关键字可以关闭fields的序列化。设置成transient的字段不参与序列化,恢复时简单的设置成默认值,如int 0, 对象句柄 null。
4. writeObject()和readObject()方法代替Externalizable
实现Serializable接口,并添加writeObject()和readObject()方法也可以控制序列化过程。但是这两个方法在类中都被定义成private,按理说外部类是不能调用的,这里序列化过程绕过了检查,这种绕过检查的机制我们普通用户是不可能接触到的。。。
private void writeObject(ObjectOutputStream stream) throws IOException;
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException;
实例:
//: SerialCtl.java //Controlling serialization by adding your own //writeObject() and readObject() methods. import java.io.*; public class SerialCtl implements Serializable { String a; transient String b; public SerialCtl(String aa, String bb) { a = "Not Transient: " + aa; b = "Transient: " + bb; } public String toString() { return a + "\n" + b; } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeObject(b); } private void readObject(ObjectInputStream stream) throws IOExcepti 4000 on, ClassNotFoundException { stream.defaultReadObject(); b = (String)stream.readObject(); } public static void main(String[] args) { SerialCtl sc = new SerialCtl("Test1", "Test2"); System.out.println("Before:\n" + sc); ByteArrayOutputStream buf = new ByteArrayOutputStream(); try { ObjectOutputStream o = new ObjectOutputStream(buf); o.writeObject(sc); // Now get it back: ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( buf.toByteArray())); SerialCtl sc2 = (SerialCtl)in.readObject(); System.out.println("After:\n" + sc2); } catch(Exception e) { e.printStackTrace(); } } } ///:~
相关文章推荐
- Java源码——对象序列化(对象的存储及读取)(Object Serialization)
- Serialize an object using XMLTag(s): XML(JAVA对象序列化成XML)
- Java对象序列化ObjectOutputStream和ObjectInputStream示例
- JHTP自测题_第十五章_文件、流和对象序列化(Files, Streams, and Object Serialization)
- 深入浅析Java Object Serialization与 Hadoop 序列化
- JHTP小结_第十五章_文件、流和对象序列化(Files, Streams, and Object Serialization)
- java 对象序列化与反序列化 FileInputSteam.readObject,writeObject
- Atiitt 对象转换json 序列化规范 Java 循环引用的解决 设置序列化层次深度 去除不必的属性 太长不方便月度 jsonObject.remove("num1"); Prety fo
- Java IO操作——对象序列化(Serializable接口、ObjectOutputStream、以及与Externalizable接口的用法和区别)
- (JAVA)从零开始之--对象输入输出流ObjectInputStream、ObjectOutputStream(对象序列化与反序列化)
- 浅析Java Object Serialization与 Hadoop 序列化
- Java的IO操作(三) - 对象的序列化、ObjectInputStream和ObjectOutputStream类
- java中对象序列化(Serialization)的注意事项
- java 序列化ObjectOutputStream 同一文件追加写对象问题的解决
- Java IO之对象的序列化、ObjectInputStream和ObjectOutputStream类
- Java 网络编程 之 传输对象 Serialization 序列化
- Java的IO操作(三) - 对象的序列化、ObjectInputStream和ObjectOutputStream类
- java语言编程IO流之对象序列化和ObjectInputStream与ObjectOutputStream
- java serialization/deserialization (序列化对象自描述)
- C++ / QT 对象序列化(Object Serialization)的实现