Java中的Serializable接口transient關鍵字,及字節、字符、對象IO


1、什么是序列化和反序列化
Serialization是一種將對象轉為為字節流的過程;deserialization是將字節流恢復為對象的過程。

2、什么情況下需要序列化
a)當你想把的內存中的對象保存到一個文件中或者數據庫中時候;
b)當你想用套接字在網絡上傳送對象的時候;
c)當你想通過RMI傳輸對象的時候;

3、如何實現序列化
將需要序列化的類實現Serializable接口就可以了,Serializable接口和Cloneable接口一樣,不含任何方法,是個標記接口。

4、代碼分析

package com.tonyluis;

import java.io.*;

public class Solution {
	public static void main(String args[]) {
		ObjectOutputStream objectos = null;
		SerializableTest myTest = new SerializableTest("str", 12, 1, "123456", 8);
		try {
			objectos = new ObjectOutputStream(new FileOutputStream("test.dat"));
			objectos.writeObject(myTest);
			objectos.flush();
			objectos.close();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		ObjectInputStream objectin;
		SerializableTest mts = null;
		try {
			objectin = new ObjectInputStream(new FileInputStream("test.dat"));
			mts = (SerializableTest) objectin.readObject();
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		System.out.println(mts);
		// 注意,沒有覆蓋equals()方法,Object類的equals()默認是地址的比較
		System.out.println(mts.equals(myTest));
	}
}

class SerializableTest implements Serializable {
	// 序列化 ID 在 Eclipse 下提供了兩種生成策略
	// 一個是固定的 1L,一個是隨機生成一個不重復的 long 類型數據(實際上是使用 JDK 工具生成)
	// 如果沒有特殊需求,就是用默認的 1L 就可以
	static final long serialVersionUID = 1L;
	String name;
	int num;
	static int staticNum;
	//transient關鍵字是不能被虛擬機默認序列化的,如果想序列化需要重寫private void writeObject(ObjectOutputStream s)和private void readObject(ObjectInputStream s)
	transient String pwd;
	transient int num0;

	SerializableTest(String name, int num, int staticNum, String pwd, int num0) {
		this.name = name;
		this.num = num;
		this.staticNum = staticNum;
		this.pwd = pwd;
		this.num0 = num0;
	}

	public String toString() {
		return "name=" + name + ",num=" + num + ",staticNum=" + staticNum + ",pwd=" + pwd + ",num0=" + num0;
	}
}

 

 輸出結果:

name=str,num=12,staticNum=1,pwd=null,num0=0
false

5.序列化前和序列化后的對象的關系


反序列化還原后的對象地址與原來的的地址不同,序列化前后對象的地址不同了,但是內容是一樣的,而且對象中包含的引用也相同。換句話說,通過序列化操作,我們可以實現對任何可Serializable對象的”深度復制(deep copy)"——這意味着我們復制的是整個對象網,而不僅僅是基本對象及其引用。對於同一流的對象,他們的地址是相同,說明他們是同一個對象,但是與其他流的對象地址卻不相同。也就說,只要將對象序列化到單一流中,就可以恢復出與我們寫出時一樣的對象網,而且只要在同一流中,對象都是同一個。

 

 

java.io.File類用於表示文件(目錄)
File類只用於表示文件(目錄)的信息(名稱、大小等),不能用於文件內容的訪問

RandomAccessFile java提供的對文件內容的訪問,既可以讀文件,也可以寫文件。
RandomAccessFile支持隨機訪問文件,可以訪問文件的任意位置

(1)java文件模型
  在硬盤上的文件是byte byte byte(字節)存儲的,是數據的集合,一個byte是8個bit,對於int就是int的后8位,對於字符(char),一個char可以理解為一個byte,但是char有ASCII編碼,byte沒有。
(2)打開文件
  有兩種模式"rw"(讀寫)  "r"(只讀)
  RandomAccessFile raf = new RandomeAccessFile(file,"rw")
  文件指針,打開文件時指針在開頭 pointer = 0;
(3) 寫方法
    raf.write(int)--->只寫一個字節(后8位),同時指針指向下一個位置,准備再次寫入
(4)讀方法
   int b = raf.read()--->讀一個字節
(5)文件讀寫完成以后一定要關閉(Oracle官方說明)


序列化與基本類型序列化
1)將類型int 轉換成4byte或將其他數據類型轉換成byte的過程叫序列化
     數據---->n byte
2)反序列化
    將n個byte 轉換成一個數據的過程
    nbyte ---> 數據
3)RandomAccessFile提供基本類型的讀寫方法,可以將基本類型數據
   序列化到文件或者將文件內容反序列化為數據
 IO流(輸入流、輸出流)
 字節流、字符流
 1.字節流
 1)InputStream、OutputStream
    InputStream抽象了應用程序讀取數據的方式
    OutputStream抽象了應用程序寫出數據的方式
 2)EOF = End   讀到-1就讀到結尾
 3)輸入流基本方法
   int  b = in.read();讀取一個字節無符號填充到int低八位.-1是 EOF
   in.read(byte[] buf)
   in.read(byte[] buf,int start,int size)
4)輸出流基本方法
  out.write(int b)  寫出一個byte到流,b的低8位
  out.write(byte[] buf)將buf字節數組都寫入到流
  out.write(byte[] buf,int start,int size)
 
 5)FileInputStream--->具體實現了在文件上讀取數據
 6)FileOutputStream 實現了向文件中寫出byte數據的方法
 7)DataOutputStream/DataInputStream
    對"流"功能的擴展,可以更加方面的讀取int,long,字符等類型數據
   DataOutputStream
        writeInt()/writeDouble()/writeUTF()

 8)BufferedInputStream&BufferedOutputStream
 這兩個流類位IO提供了帶緩沖區的操作,一般打開文件進行寫入
 或讀取操作時,都會加上緩沖,這種流模式提高了IO的性能
 從應用程序中把輸入放入文件,相當於將一缸水倒入到另一個缸中:
 FileOutputStream--->write()方法相當於一滴一滴地把水“轉移”過去
 DataOutputStream-->writeXxx()方法會方便一些,相當於一瓢一瓢把水“轉移”過去
 BufferedOutputStream--->write方法更方便,相當於一飄一瓢先放入桶中,再從桶中倒入到另一個缸中,性能提高了
   
   
 2.字符流
 1) 編碼問題
 2)認識文本和文本文件
 java的文本(char)是16位無符號整數,是字符的unicode編碼(雙字節編碼)
 文件是byte byte byte ...的數據序列
文本文件是文本(char)序列按照某種編碼方案(utf-8,utf-16be,gbk)序列化為byte的存儲結果
3)字符流(Reader Writer)---->操作的是文本文本文件
字符的處理,一次處理一個字符
字符的底層任然是基本的字節序列
字符流的基本實現
   InputStreamReader   完成byte流解析為char流,按照編碼解析
   OutputStreamWriter  提供char流到byte流,按照編碼處理  
   
   FileReader/FileWriter
 字符流的過濾器
   BufferedReader   ---->readLine 一次讀一行
   BufferedWriter/PrintWriter   ---->寫一行    
   
   
3.對象的序列化,反序列化
1)對象序列化,就是將Object轉換成byte序列,反之叫對象的反序列化
2)序列化流(ObjectOutputStream),是過濾流----writeObject
   反序列化流(ObjectInputStream)---readObject

3)序列化接口(Serializable)
   對象必須實現序列化接口 ,才能進行序列化,否則將出現異常
   這個接口,沒有任何方法,只是一個標准
 
4) transient關鍵字
    private void writeObject(java.io.ObjectOutputStream s)
                throws java.io.IOException
    private void readObject(java.io.ObjectInputStream s)
                throws java.io.IOException, ClassNotFoundException
                
   分析ArrayList源碼中序列化和反序列化的問題
 
5)序列化中 子類和父類構造函數的調用問題


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM