您的位置:首页 > 移动开发 > Objective-C

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;

实例:

//: 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();
}
}
} ///:~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐