1. 程式人生 > 其它 >序列化和反序列化的詳解

序列化和反序列化的詳解

序列化: 就是把記憶體中的物件,轉換成位元組序列(或其他資料傳輸協議)以便於儲存(持久化)和網路傳輸;

反序列化: 就是將收到位元組序列(或其他資料傳輸協議)或者是硬碟的持久化資料,轉換成記憶體中的物件。

像資料庫驅動類,就不能序列化,因為序列化後,localhost找不到地址,不能進行反序列化。

1、Java 序列化

是一個重量級序列化框架(Serializable),它會把這個物件的方方面面的資訊都序列化出去,產生的二進位制序列體積臃腫龐大,但是資訊很全。

public class SerDeDemo {

    public static void main(String[] args) throws Exception {
        Person p = new Person("周洋舟", 288899998.8, 18);
        
       // jdk中自帶的序列化工具,它會把這個物件的方方面面的資訊都序列化出去,產生的二進位制序列體積臃腫龐大,但是資訊很全
	   /*ObjectOutputStream objout = new ObjectOutputStream(new FileOutputStream("d:/p.obj"));
		        objout.writeObject(p);
		        objout.close();*/
       
        DataOutputStream dataout = new DataOutputStream(new FileOutputStream("d:/p2.obj"));
        dataout.writeUTF(p.getName());
        dataout.writeDouble(p.getSalary());
        dataout.writeInt(p.getAge());

        DataOutputStream dataout2 = new DataOutputStream(new FileOutputStream("d:/p3.obj"));
        dataout2.writeInt(18);
        dataout2.writeUTF("18");

    }

}

  

2、hadoop序列化

hadoop 自己開發了一套序列化機制(Writable),精簡、高效,需要實現write方法 和 readFields方法。

public class Person2 implements Writable {
    private String name;
    private Double salary;
    private int age;

    public Person2() {
    }

    public Person2(String name, Double salary, int age) {
        this.name = name;
        this.salary = salary;
        this.age = age;
    }


    public void write(DataOutput dataOutput) throws IOException {
        dataOutput.writeUTF(this.name);
        dataOutput.writeDouble(this.salary);
        //dataOutput.writeInt(this.age);
    }

    public void readFields(DataInput dataInput) throws IOException {
        this.name = dataInput.readUTF();
        this.salary = dataInput.readDouble();
        //this.age = dataInput.readInt();

    }
}

  

3、spark序列化

spark中將物件序列化,預設呼叫jdk的objectoutputstream(serializable),所以,我們在spark程式碼中,一般都要修改序列化器,可以用kryo序列化框架,kryo序列化框架的序列化結果要比jdk的序列化結果更精簡(少了一些類的元資訊)。

object SparkSerde {

  def main(args: Array[String]): Unit = {

    val spark1 = SparkSession.builder.config("spark.serializer", classOf[KryoSerializer].getName).appName("").master("local").getOrCreate
    import spark1.implicits._
    spark1.createDataset(Seq(new Person("zz", 1888.8, 28)));
    // 上面的做法,kryo在序列化時,還是會帶上一些必要的類元資訊,以便於下游task能正確反序列化

    // 下面的做法,可以提前將這些可能要被序列化的型別,註冊到kryo的對映表中,這樣,kryo在序列化時就不需要序列化類元資訊了
    val conf = new SparkConf
    conf.set("spark.serializer", "org.apache.spark.serializer.KryoSerializer")
    conf.registerKryoClasses(Array(classOf[Person],classOf[Person2]))
    val spark2 = SparkSession.builder()
      .config(conf)
      .master("local")
      .appName("序列化案例")
      .getOrCreate()
  }

}

  更多java、大資料學習面試資料,請掃碼關注我的公眾號:

專注於大資料和java開發,學習交流可以關注我的公眾號:javaydsj