序列化就是把內存中的對象,轉換成字節序列(或其餘數據傳輸協議)以便於存儲(持久化)和網絡傳輸。 java
反序列化就是將收到字節序列(或其餘數據傳輸協議)或者是硬盤的持久化數據,轉換成內存中的對象。apache
Hadoop擁有一套本身的序列化機制。網絡
Java的序列化是一個重量級序列化框架(Serializable),一個對象被序列化後,會附帶不少額外的信息(各類校驗信息,header,繼承體系等),不便於在網絡中高效傳輸。因此,hadoop本身開發了一套序列化機制(Writable),他具備精簡、高效的特色。框架
Hadoop之父Doug Cutting(道格卡丁)解釋道:「由於Java的序列化機制太過複雜了,而我認爲須要有一個精簡的機制,能夠用於精確控制對象的讀和寫,這個機制將是Hadoop的核心。使用Java序列化雖然能夠得到一些控制權,但用起來很是糾結。不用RMI(遠程方法調用)也是出於相似的考慮。」ide
咱們經過經常使用的Java數據類型對應的hadoop數據序列化類型 |Java類型|Hadoop Writable類型| |-|-| |boolean |BooleanWritable| |byte |ByteWritable| |int |IntWritable| |float |FloatWritable| |long |LongWritable| |double |DoubleWritable| |string |Text| |map |MapWritable| |array| ArrayWritable|函數
在具體案例中,咱們能夠根據實際需求,若是類型能夠用簡單類型勝任的話,在此表中尋找到對應的參考。oop
不少狀況下,基礎類型是沒法知足咱們的業務需求的,一般咱們的輸入輸出極可能都是一些實體化的類型映射。基於這種狀況,咱們就須要自定義writable類型。this
自定義bean對象要想序列化傳輸,必須實現序列化接口,須要參考以下規則:code
setter方法中,推薦再增長一個set方法,用於一次性設置全部的合併字段。對象
以下是一個簡單的自定義Writable類型
package com.zhaoyi.phoneflow; import org.apache.hadoop.io.Writable; import java.io.DataInput; import java.io.DataOutput; import java.io.IOException; public class FlowBean implements Writable { private long upFlow;// 上行流量 private long downFlow;// 下行流量 private long totalFlow;// 總流量 // 無參構造 public FlowBean() { } public FlowBean(long upFlow, long downFlow) { this.upFlow = upFlow; this.downFlow = downFlow; this.totalFlow = upFlow + downFlow; } // 序列化 public void write(DataOutput out) throws IOException { out.writeLong(upFlow); out.writeLong(downFlow); out.writeLong(totalFlow); } // set方法,一次性設置屬性 public void set(long upFlow, long downFlow){ this.upFlow = upFlow; this.downFlow = downFlow; this.totalFlow = upFlow + downFlow; } // 反序列化 - 順序和序列化保持一致 public void readFields(DataInput in) throws IOException { this.upFlow = in.readLong(); this.downFlow = in.readLong(); this.totalFlow = in.readLong(); } public long getUpFlow() { return upFlow; } public long getDownFlow() { return downFlow; } public long getTotalFlow() { return totalFlow; } public void setUpFlow(long upFlow) { this.upFlow = upFlow; } public void setDownFlow(long downFlow) { this.downFlow = downFlow; } public void setTotalFlow(long totalFlow) { this.totalFlow = totalFlow; } // 使用製表符分隔 @Override public String toString() { return "upFlow=" + upFlow + "\t" + downFlow + "\t" + totalFlow; } }