您好,登錄后才能下訂單哦!
序列化就是將內存中的對象,轉換成字節序列(或者按照其他數據傳輸協議轉換),以便于持久化存儲到磁盤中以及網絡傳輸
一般情況下,對象只存儲在本地的內存中,只允許本地的進程調用。而隨著分布式程序的出現,需要在不同的主機上不同進程調用對象,這就需要將對象通過網絡傳輸到另外的主機上。但是對象不經過處理無法通過網絡傳輸,而通過序列化處理之后,對象可以通過網絡傳輸了。
java中自行實現了序列化方案,只要定義一個類的時候實現 Serializable 接口,那么java內部就會自動實現相應的序列化。如:
public class Test implements Serializable{
//這個序列化號是必須的,用于標識該類
private static final long serialVersionUID = xxxx;
}
但是由于Java中的序列化接口實現的時候,會附帶很多額外的信息,如各種校驗信息,header,繼承體系等。不便于在網絡上高效傳輸(性能不高)。所以hadoop自己額外實現了序列化的機制,體積短小,占用帶寬低,序列化和反序列化快速
hadoop中以實現 Writable 這個接口的類,就可以序列化。而且hadoop實現了許多基本類型的可序列化的類。依賴圖如下所示:
? 圖 2.1 hadoop序列化依賴圖
可以看到所有的可序列化的類都實現了 WritableComparable 這個接口,這個接口同時繼承了 Writable 以及 Comparable 接口。下面看看這個這三個接口:
//WritableComparable.java
public interface WritableComparable<T> extends Writable, Comparable<T> {
}
/*
空的接口
*/
//Writable.java
public interface Writable {
void write(DataOutput var1) throws IOException;
void readFields(DataInput var1) throws IOException;
}
/*
主要包含讀和寫序列化對象的方法
*/
//Comparable.java
public interface Comparable<T> {
public int compareTo(T o);
}
/*
提供序列化對象間比較的方法
*/
java類型 | hadoop writable類型 |
---|---|
boolean | BooleanWritable |
byte | ByteWritable |
Int | IntWritable |
float | FloatWritable |
long | LongWritable |
double | DoubleWritable |
string | Text |
map | MapWritable |
array | ArrayWritable |
下面挑個IntWritable這個常用的序列化類來看看源碼
package org.apache.hadoop.io;
import java.io.DataInput;
import java.io.DataOutput;
import java.io.IOException;
import org.apache.hadoop.classification.InterfaceAudience.Public;
import org.apache.hadoop.classification.InterfaceStability.Stable;
@Public
@Stable
public class IntWritable implements WritableComparable<IntWritable> {
private int value;
public IntWritable() {
}
public IntWritable(int value) {
this.set(value);
}
public void set(int value) {
this.value = value;
}
public int get() {
return this.value;
}
//這里是實現了 writable 接口的方法
public void readFields(DataInput in) throws IOException {
this.value = in.readInt();
}
public void write(DataOutput out) throws IOException {
out.writeInt(this.value);
}
//序列化對象的equals比較方法
public boolean equals(Object o) {
if (!(o instanceof IntWritable)) {
return false;
} else {
IntWritable other = (IntWritable)o;
return this.value == other.value;
}
}
public int hashCode() {
return this.value;
}
//比較對象大小的方法
public int compareTo(IntWritable o) {
int thisValue = this.value;
int thatValue = o.value;
return thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1);
}
public String toString() {
return Integer.toString(this.value);
}
/*這里是關鍵,將下面的Comparator內部類作為默認的比較方法。
因為這里采用靜態代碼塊的方式,所以只要該類載入時,就會執行該代碼塊,直接創建 Comparator對象,后面無需通過外部類創建對象的方式來調用 compare方法,因為對象已經提前創建好了。比起上的 compareTo 方法,還要手動創建一個外部類對象才能調用 compareTo 方法,這里可以直接調用,效率要快。
*/
static {
WritableComparator.define(IntWritable.class, new IntWritable.Comparator());
}
//這個內部類也實現了 compare比較方法
public static class Comparator extends WritableComparator {
public Comparator() {
super(IntWritable.class);
}
public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
int thisValue = readInt(b1, s1);
int thatValue = readInt(b2, s2);
return thisValue < thatValue ? -1 : (thisValue == thatValue ? 0 : 1);
}
}
}
其他short,long的序列化類的實現也是類似的。
要點:
(1)必須實現 Writable接口
(2)必須有無參構造方法,因為反序列化時需要反射調用無參構造方法
(3)重寫序列化方法
public void write(DataOutput out) throws IOException{
//DataOutput接口中定義了每個基本類型序列化的方法,這里以Long為例
out.writeLong(upFlow);
out.writeLong(downFlow);
out.writeLong(sumFlow);
}
(4)重寫反序列化方法
public void readFields(DataInput in) throws IOException{
upFlow = in.readLong();
downFlow = in.readLong();
sumFlow = in.readLong();
}
(5)序列化寫入和反序列化讀取時要注意,寫入和讀取的順序必須完全一致
(6)按照需要可以重寫 toSting 方法,便于保存在文件中的內容
(7)如果該自定義序列化類是作為鍵值對中的key使用的話,因為MapReduce中會以key進行排序,那么就會涉及到 key 的比較問題。所以需要實現 Comparable 接口。而該接口就得實現 compareTo 方法
public int compareTo(Test o) {
return (-1 | 0 |1 ); 表示小于,等于,大于三種結果
}
首先屬性中的自定義類也是需要實現序列化接口的。所以下面的DateDimension和ContactDimension都是已經實現序列化的了。
public class ComDimension extends BaseDimension {
private DateDimension dateDimension = new DateDimension();
private ContactDimension contactDimension = new ContactDimension();
//序列化就直接調用類的write方法即可,按照下面的形式
@Override
public void write(DataOutput dataOutput) throws IOException {
this.dateDimension.write(dataOutput);
this.contactDimension.write(dataOutput);
}
@Override
public void readFields(DataInput dataInput) throws IOException {
this.dateDimension.readFields(dataInput);
this.contactDimension.readFields(dataInput);
}
}
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。