序列化: 是将内存中的对象转换称为字节序列,以便持久化到磁盘中或用于网络传输
反序列化: 将字节序列转换称为内存中的对象
1.2 JDK 序列化反序列化Java 中,如果需要序列化,需要实现 java.io.Serializable 接口,利用序列化版本ID serialVersionUID 来标识版本。
JDK 需要借助 ObjectOutputStream (writeObject(Object))和 ObjectInputStream (readObject())分别实现序列化反序列化。
1.3 Hadoop 序列化反序列化Hadoop 不适用 JDK 序列化,是因为利用 Serializable 序列化后会附带很多额外的信息,不便于数据的网络传输。
Hadoop 实现的序列化机制为 Writable。
1.4 Hadoop 序列化的意义Hadoop 在集群之间进行通讯或者 RPC 调用的时候,需要序列化,而且要求序列化要快,且体积要小,占用带宽要小。所以必须理解 Hadoop 的序列化机制。
序列化和反序列化在分布式数据处理领域经常出现:进程通信和永久存储。然而Hadoop中各个节点的通信是通过远程调用(RPC)实现的,那么就不能使用 JDK 序列化,所以 Hadoop 自己实现了一套序列化机制。
Hadoop 序列化特点:
- 紧凑:高校使用存储空间
- 快速:读写数据的额外开销小
- 可扩展:原始序列化方式支持新协议的报文
- 互操作:支持多种语言的交互
| Java 类型 | Hadoop Writable 类型 |
|---|---|
| boolean | BooleanWritable |
| byte | ByteWritable |
| int | IntWritable |
| float | FloatWritable |
| long | LongWritable |
| double | DoubleWritable |
| string | Text |
| map | MapWritable |
| array | ArrayWritable |
Writable 用于在对象和字节序列之间做转换。
自定义实现需要注意几点:
- 必须要实现 Writable 接口
- 需要提供无参构造,应为反序列化需要反射调用空参构造函数
- 重写序列、反序列方法,且序列和反序列的顺序保持一致
- 如果后期需要指定 key 排序,还需要实现 Comparable 接口
Writable 接口中只有两个方法
- write:用于序列化操作
- readFields:用于反序列化操作
public interface Writable {
void write(DataOutput var1) throws IOException;
void readFields(DataInput var1) throws IOException;
}
如果需要比较,我们可以直接实现WritableComparable 接口,该接口只是继承了两个接口类,因此还需要实现 Comparable 的 compareTo 方法。
@Public @Stable public interface WritableComparableextends Writable, Comparable { }
public interface Comparable2.2 自定义 Bean{ public int compareTo(T o); }
比如:对日志文件进行相关信息统计
import org.apache.hadoop.io.Writable; import org.apache.hadoop.io.WritableComparable; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; public class WritableUser implements WritableComparable3. 写在最后{ long id; String name; int age; boolean sex; int money; // 必须实现 Writable 接口 ======================================== @Override public void write(DataOutput dataOutput) throws IOException { dataOutput.writeLong(this.id); dataOutput.writeUTF(this.name); dataOutput.writeInt(this.age); dataOutput.writeBoolean(this.sex); dataOutput.writeInt(this.money); } @Override public void readFields(DataInput dataInput) throws IOException { this.id = dataInput.readLong(); this.name = dataInput.readUTF(); this.age = dataInput.readInt(); this.sex = dataInput.readBoolean(); this.money = dataInput.readInt(); } @Override public int compareTo(WritableUser o) { if (this.age == o.age){ return -Integer.compare( this.money, o.money); } else { return -Integer.compare( this.age, o.age); } } // 提供无参构造,以便反序列化通过反射调用 public WritableUser() { } public WritableUser(long id, String name, int age, boolean sex, int money) { this.id = id; this.name = name; this.age = age; this.sex = sex; this.money = money; } // 提供 set 方法,方便后期使用 public void set(long id, String name, int age, boolean sex, int money) { this.id = id; this.name = name; this.age = age; this.sex = sex; this.money = money; } @Override public String toString() { return "WritableUser{" + "id=" + id + ", name='" + name + ''' + ", age=" + age + ", sex=" + sex + ", money=" + money + '}'; } }
只需要序列化时,实现 Writable ,如果还需要排序,可实现 WritableComparable 。
如果想要降序排列,在返回值前加个负号(-)
❤️ END ❤️



