天天看點

Treasure Of JAVA——JAVA的IO流(JAVA面試題)Java 的 IO

Java 的 IO

1. Java 中有幾種類型的流

​ 按照流的方向:輸入流(inputStream)和輸出流(outputStream)。

​ 按照實作功能分:節點流(可以從或向一個特定的地方(節點)讀寫資料。如 FileReader)和處理流(是對一個

已存在的流的連接配接和封裝,通過所封裝的流的功能調用實作資料讀寫。如 BufferedReader。處理流的構造方法總是要

帶一個其他的流對象做參數。一個流對象經過其他流的多次包裝,稱為流的連結。)

​ 按照處理資料的機關:位元組流和字元流。位元組流繼承于 InputStream 和 OutputStream,字元流繼承于

InputStreamReader 和 OutputStreamWriter。

Treasure Of JAVA——JAVA的IO流(JAVA面試題)Java 的 IO
Treasure Of JAVA——JAVA的IO流(JAVA面試題)Java 的 IO

2. 位元組流如何轉為字元流

​ 位元組輸入流轉字元輸入流通過 InputStreamReader 實作,該類的構造函數可以傳入 InputStream 對象。

​ 位元組輸出流轉字元輸出流通過 OutputStreamWriter 實作,該類的構造函數可以傳入 OutputStream 對象。

3. 如何将一個 java 對象序列化到檔案裡

​ 在 java 中能夠被序列化的類必須先實作 Serializable 接口,該接口沒有任何抽象方法隻是起到一個标記作用。

//對象輸出流
	ObjectOutputStream objectOutputStream = 
	new ObjectOutputStream(new FileOutputStream(new File("D://obj")));
	objectOutputStream.writeObject(new User("zhangsan", 100));
	objectOutputStream.close();
	//對象輸入流
	ObjectInputStream objectInputStream = 
	new ObjectInputStream(new FileInputStream(new File("D://obj")));
	User user = (User)objectInputStream.readObject();
	System.out.println(user);
	objectInputStream.close();
           

4. 位元組流和字元流的差別

​ 位元組流讀取的時候,讀到一個位元組就傳回一個位元組; 字元流使用了位元組流讀到一個或多個位元組(中文對應的位元組

數是兩個,在 UTF-8 碼表中是 3 個位元組)時。先去查指定的編碼表,将查到的字元傳回。 位元組流可以處理所有類型數

據,如:圖檔,MP3,AVI 視訊檔案,而字元流隻能處理字元資料。隻要是處理純文字資料,就要優先考慮使用字元

流,除此之外都用位元組流。位元組流主要是操作 byte 類型資料,以 byte 數組為準,主要操作類就是 OutputStream、

InputStream

​ 字元流處理的單元為 2 個位元組的 Unicode 字元,分别操作字元、字元數組或字元串,而位元組流處理單元為 1 個字

節,操作位元組和位元組數組。是以字元流是由 Java 虛拟機将位元組轉化為 2 個位元組的 Unicode 字元為機關的字元而成的,

是以它對多國語言支援性比較好!如果是音頻檔案、圖檔、歌曲,就用位元組流好點,如果是關系到中文(文本)的,用

字元流好點。在程式中一個字元等于兩個位元組,java 提供了 Reader、Writer 兩個專門操作字元流的類。

5. 如何實作對象克隆?

有兩種方式。

​ 1. 實作 Cloneable 接口并重寫 Object 類中的 clone()方法;

​ 2. 實作 Serializable 接口,通過對象的序列化和反序列化實作克隆,可以實作真正的深度克隆,代碼如下。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class MyUtil {
	private MyUtil() {
		throw new AssertionError();
	}
	@SuppressWarnings("unchecked")
	public static <T extends Serializable> T clone(T obj) throws Exception {
		ByteArrayOutputStream bout = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bout);
		oos.writeObject(obj);
		ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
		ObjectInputStream ois = new ObjectInputStream(bin);
		return (T) ois.readObject();
		// 說明:調用 ByteArrayInputStream 或 ByteArrayOutputStream 對象的 close 方法沒有任何意義
		// 這兩個基于記憶體的流隻要垃圾回收器清理對象就能夠釋放資源,這一點不同于對外部資源(如檔案流)的釋放
	}
}
           

測試代碼:

import java.io.Serializable;
/**
* 人類
*/
class Person implements Serializable {
	private static final long serialVersionUID = -9102017020286042305L;
	private String name; // 姓名
	private int age; // 年齡
	private Car car; // 座駕
	public Person(String name, int age, Car car) {
		this.name = name;
		this.age = age;
		this.car = car;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age; 
    }
	public void setAge(int age) {
		this.age = age;
	}
	public Car getCar() {
		return car;
	}
	public void setCar(Car car) {
		this.car = car;
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
	}
}
           
/**
* 小汽車類
*/
class Car implements Serializable {
	private static final long serialVersionUID = -5713945027627603702L;
	private String brand; // 品牌
	private int maxSpeed; // 最高時速
	public Car(String brand, int maxSpeed) {
		this.brand = brand;
		this.maxSpeed = maxSpeed;
	}
	public String getBrand() {
		return brand;
	}
	public void setBrand(String brand) {
		this.brand = brand;
	}
	public int getMaxSpeed() {
		return maxSpeed;
	}
	public void setMaxSpeed(int maxSpeed) {
		this.maxSpeed = maxSpeed;
	}
	@Override
	public String toString() {
		 eturn "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]";
    }
}
           
class CloneTest {
	public static void main(String[] args) {
        try {
		Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300));
		Person p2 = MyUtil.clone(p1); // 深度克隆
		p2.getCar().setBrand("BYD");
		// 修改克隆的 Person 對象 p2 關聯的汽車對象的品牌屬性
		// 原來的 Person 對象 p1 關聯的汽車不會受到任何影響
		// 因為在克隆 Person 對象時其關聯的汽車對象也被克隆了
		System.out.println(p1);
		} catch (Exception e) {
			e.printStackTrace();
		}	
    }
}
           

​ 注意:基于序列化和反序列化實作的克隆不僅僅是深度克隆,更重要的是通過泛型限定,可以檢查出要克隆的對

象是否支援序列化,這項檢查是編譯器完成的,不是在運作時抛出異常,這種是方案明顯優于使用 Object 類的 clone

方法克隆對象。讓問題在編譯的時候暴露出來總是好過把問題留到運作時。

6. 什麼是 java 序列化,如何實作 java 序列化?

​ 序列化就是一種用來處理對象流的機制,所謂對象流也就是将對象的内容進行流化。可以對流化後的對象進行讀

寫操作,也可将流化後的對象傳輸于網絡之間。序列化是為了解決在對對象流進行讀寫操作時所引發的問題。

​ 序 列 化 的 實 現 : 将 需 要 被 序 列 化 的 類 實 現 Serializable 接 口 , 該 接 口 沒 有 需 要 實 現 的 方 法 ,

implements Serializable 隻是為了标注該對象是可被序列化的,然後使用一個輸出流(如:FileOutputStream)來構造

一個 ObjectOutputStream(對象流)對象,接着,使用 ObjectOutputStream 對象的 writeObject(Object obj)方法就

可以将參數為 obj 的對象寫出(即儲存其狀态),要恢複的話則用輸入流。

原文連結:https://www.cnblogs.com/yangchunze/p/6728086.html