Hadoop序列化&Java序列化

我的梦境 提交于 2019-12-07 19:51:56

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的序列化结果紧凑而快速

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!