Java序列化机制将对象装换为连续的byte数据, 这些数据可以在以后还原(反序列化)成原来的对象
Java中, 要想一个类的实例可被序列化, 该类须实现Serializable接口. Serializable接口是一个标志, 没有任何方法, 其定义如下
public interface Serializable {
}
定义一个类Block1, 该类实现了Serializable接口
class Block1 implements Serializable {
private int one = 1;
private int two = 2;
private int three = 3;
@Override
public String toString() {
return "Block1 [one=" + one + ", two=" + two + ", three=" + three + "]";
}
}
定义一个类JavaSerializeTest, 测试Java序列化机制
public class JavaSerializeTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Block1 block = new Block1();
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
try {
// 创建一个ByteArrayOutputStream对象baos
baos = new ByteArrayOutputStream();
// 装饰ByteArrayOutputStream对象baos, 得到ObjectOutputStream对象oos
oos = new ObjectOutputStream(baos);
// 对block进行序列化, 序列化到baos中
oos.writeObject(block);
// 从字节数组输出流baos中得到字节数组
byte[] bytes = baos.toByteArray();
System.out.println("序列化Block1对象为byte数组, byte数组长度为:" + bytes.length);
// 以字节数组bytes创建ByteArrayInputStream对象, 再把这个对象装饰成ObjectInputStream对象ois
ois = new ObjectInputStream(new ByteArrayInputStream(bytes));
// 调用ObjectInputStream对象ois的readObject()方法, 实现反序列化, 返回一个Block1对象block1
Block1 block1 = (Block1) ois.readObject();
System.out.println("byte数组反序列化, 还原成Block1对象: " + block1);
} finally {
//关闭流
}
}
}
Console输出:
序列化Block1对象为byte数组, byte数组长度: 72
byte数组反序列化, 还原成Block1对象: Block1 [one=1, two=2, three=3]
ObjectOutputStream提供了一些writeX()方法, 包括writeInt(), writeLong(), writeFloat(), writeUTF()...
JavaAPI:
public final void writeObject(Object obj) throws IOException
将指定的对象写入ObjectOutputStream。对象的类、类的签名,以及类及其所有父类型的非瞬态和非静态字段的值都将被写入
由于Java的序列化机制太过强大, 可以看出只有3个属性(都为int类型,一共12个字节)的Block1对象block, 序列化后生成的字节数组却有72个字节, 因此对于Hadoop来说, 需要一个新的序列化机制
Hadoop中, 要想一个类的实例可被序列化, 该类须实现Writable接口.
Writable接口有两个方法, write()序列化和readFields()反序列化, 其定义如下:
public interface Writable {
/*
* 将对象(this)的属性字段序列化到输出流DataOuput out中。
*/
void write(DataOutput out) throws IOException;
/*
* 从输入流DataInput in中读取属性字段信息,重组为(this)对象,这是一个反序列化操作。
*/
void readFields(DataInput in) throws IOException;
}
定义一个类Block2, 该类实现了Writable接口
class Block2 implements Writable {
private int one = 1;
private int two = 2;
private int three = 3;
/*
* 将对象(this)的属性字段序列化到输出流DataOuput out中。
*/
@Override
public void write(DataOutput out) throws IOException {
out.writeInt(one);
out.writeInt(two);
out.writeInt(three);
}
/*
* 从输入流DataInput in中读取属性字段信息,重组为(this)对象,这是一个反序列化操作。
*/
@Override
public void readFields(DataInput in) throws IOException {
one = in.readInt();
// 为了看出来反序列化效果, 交换第two和three,
three = in.readInt(); // two=3
two = in.readInt(); // three=2
}
@Override
public String toString() {
return "Block2 [one=" + one + ", two=" + two + ", three=" + three + "]";
}
}
PS: write()方法中out.writeX(x)和readFields()方法中x = in.readX()顺序必须一致, 否则无法保证数据的正确性
定义一个类HadoopSerializeTest, 测试Hadoop序列化机
public class HadoopSerializeTest {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Block2 block = new Block2();
ByteArrayOutputStream baos = null;
DataOutputStream dos = null;
DataInputStream dis = null;
try {
// 创建一个ByteArrayOutputStream对象baos
baos = new ByteArrayOutputStream();
// 装饰ByteArrayOutputStream对象baos, 得到DataOutputStream对象dos
dos = new DataOutputStream(baos);
// 对block进行序列化, 序列化到baos中
block.write(dos);
// 从baos中得到字节数组
byte[] bytes = baos.toByteArray();
System.out.println("序列化Block2对象为byte数组, byte数组长度为: " + bytes.length);
// 以字节数组bytes创建ByteArrayInputStream对象, 再把这个对象装饰成DataInputStream对象dis
dis = new DataInputStream(new ByteArrayInputStream(bytes));
Block2 block1 = new Block2();
System.out.println("未反序列化的Block2对象: " + block1);
// 调用block1的readFields(DataInput)方法, 实现反序列化, 交换two和three的值
block1.readFields(dis);
System.out.println("byte数组反序列化, 还原成Block2对象:" + block1);
} finally {
//关闭流
}
}
}
Console输出:
序列化Block2对象为byte数组, byte数组长度: 12
未反序列化的Block2对象: Block2 [one=1, two=2, three=3]
byte数组反序列化, 还原成Block2对象: Block2 [one=1, two=3, three=2]
由于Block2对象block序列化时只输出3个int, 序列化后生成的字节数组只有12个字节, 和Java的序列化机制的输出结果(72个字节)对比, Hadoop的序列化结果紧凑而快速
来源:oschina
链接:https://my.oschina.net/u/2503731/blog/658670