在基于网络编程的项目中,经常会遇到需要将某些参数进行序列化之后再进行传输,在接收方再进行反序列化操作。普遍的做法是让实体类实现Serializable接口,但是当涉及很多实体类或者说需要序列化的实体类型不确定时(后期会有增加),那使用实现Serializable接口的方式在编程模型上不符合低耦合的原则。所以采用引用工具类的方式去处理。
public abstract class SerializationUtils {
/**
* Serialize the given object to a byte array.
* @param object the object to serialize
* @return an array of bytes representing the object in a portable fashion
*/
public static byte[] serialize(Object object) {
if (object == null) {
return null;
}
ByteArrayOutputStream baos = new ByteArrayOutputStream(1024);
try {
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(object);
oos.flush();
}
catch (IOException ex) {
throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), ex);
}
return baos.toByteArray();
}
/**
* Deserialize the byte array into an object.
* @param bytes a serialized object
* @return the result of deserializing the bytes
*/
public static Object deserialize(byte[] bytes) {
if (bytes == null) {
return null;
}
try {
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
return ois.readObject();
}
catch (IOException ex) {
throw new IllegalArgumentException("Failed to deserialize object", ex);
}
catch (ClassNotFoundException ex) {
throw new IllegalStateException("Failed to deserialize object type", ex);
}
}
}
* ByteArrayOutputStream类是在创建它的实例时,程序内部创建一个byte型别数组的缓冲区,
* 然后利用ByteArrayOutputStream和ByteArrayInputStream的实例向数组中写入或读出byte型数据。
* 在网络传输中我们往往要传输很多变量,我们可以利用ByteArrayOutputStream把所有的变量收集到一起,然后一次性把数据发送出去。
* 具体用法如下:
* ByteArrayOutputStream: 可以捕获内存缓冲区的数据,转换成字节数组
* ByteArrayInputStream: 可以将字节数组转化为输入流
* 代码实现如下所示:
* ByteArrayOutputStream把内存中的数据读到字节数组中,
* 而ByteArrayInputStream又把字节数组中的字节以流的形式读出,
* 实现了对同一个字节数组的操作.
public static void main(String[] args) throws IOException {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
DataOutputStream dout = new DataOutputStream(bout);
String name = "XYY";
int age = 27;
dout.writeUTF(name);
dout.writeInt(age);
byte[] buff = bout.toByteArray();
ByteArrayInputStream bin = new ByteArrayInputStream(buff);
DataInputStream dis = new DataInputStream(bin);
String newName = dis.readUTF();
int newAge = dis.readInt();
System.out.println(newName + ":" + newAge);
}
* java.io包中,提供了ObjectInputStream和ObjectOutputStream将数据流功能扩展至可读写对象 。在ObjectInputStream 中用readObject()方法可以直接读取一个对象,ObjectOutputStream中用writeObject()方法可以直接将对象保存到输出流中。
Java的"对象序列化"能让你将一个实现了Serializable接口的对象转换成byte流,这样日后要用这个对象时候,你就能把这些byte数据恢复出来,并据此重新构建那个对象了。
在实际使用对象序列化时,一种应用场景是将对象序列化到持久化存储(本地硬盘),我们此时不想做文件解析,也不想有人读懂这个持久化文件,当我们需要时,
可以直接采用反序列化将保存的文件生成为对象;另一种应用场景是在网络传输过程中,此时对象会在不同主机上传播,序列化会将对象转成码流由对端进行解析,
这个解析过程不需要人参与。
在序列化时,有几点要注意的:
1:当一个对象被序列化时,只保存对象的非静态成员变量(包括声明为private的变量),不能保存任何的成员方法和静态的成员变量。
2:如果一个对象的成员变量是一个对象,那么这个对象的数据成员也会被序列化。
3:如果一个可序列化的对象包含对某个不可序列化的对象的引用,那么整个序列化操作将会失败,并且会抛出一个NotSerializableException。我们可以将这个引用标记为transient,那么对象仍然可以序列化。
序列化是干什么的简单说就是为了保存在内存中的各种对象的状态,并且可以把保存的对象状态再读出来。虽然你可以用你自己的各种各样的方法来保存Object States,但是Java给你提供一种应该比你自己好的保存对象状态的机制,那就是序列化。
什么情况下需要序列化
a)当你想把的内存中的对象保存到一个文件中或者数据库中时候;
b)当你想用套接字在网络上传送对象的时候;
c)当你想通过RMI传输对象的时候;