勿以惡小而爲之,勿以善小而不爲--------------------------劉備
勸諸君,多行善事積福報,莫作惡
上一章簡單介紹了 DataOutputStream和DataInputStream(八),如果沒有看過,請觀看上一章
一. 爲什麼要序列化?
上一章節寫入文件的員工列表信息數據:
id | name | sex | age | desc |
---|---|---|---|---|
1 | 老蝴蝶 | 男 | 20 | 一個好人 |
2 | 蝴蝶 | 男 | 21 | 一個人 |
3 | 嶽澤霖 | 男 | 22 | 快樂的人 |
4 | 嶽建立 | 男 | 23 | 想要快樂的人 |
通過 DataOutputStream 和 DataInputStream ,發現太複雜了,需要固定的格式進行處理, 當數據信息複雜時,就瘋了。
我們發現,員工的信息可以封裝成一個對象,如 Person 對象, 該對象裏面有 id,name,sex,age,desc 屬性。
public class Person {
private int id;
private String name;
private char sex;
private int age;
private String desc;
public Person() {
}
public Person(int id, String name, char sex, int age, String desc) {
this.id = id;
this.name = name;
this.sex = sex;
this.age = age;
this.desc = desc;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
", sex=" + sex +
", age=" + age +
", desc='" + desc + '\'' +
'}';
}
}
我們存儲時,能直接存儲對象就好了, 取數據時,直接取對象, 方便操作。
這種形式,其實就是序列化。
序列化是將對象存儲到文件裏面, 反序列化是將文件轉換成對象。
序列化和反序列化所需要的對象爲 ObjectOutputStream 和 ObjectInputStream.
二. 序列化 ObjectOutputStream
二.一 方法
二.一.一 構造方法
二.一.一.一 方法
方法 | 作用 |
---|---|
ObjectOutputStream(OutputStream out) | 傳入 outputStream 對象 |
二.一.一.二 演示
@Test
public void objConTest() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data2.txt");
//傳入 outputStream
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
}
二.一.二 寫入方法
方法 | 作用 |
---|---|
void flush() | 刷新此數據輸出流 |
void writeInt(int v) | 寫入 int 類型的值 |
void writeLong(long v) | 寫入long 類型的值 |
void writeFloat(float v) | 寫入float 值 |
void writeDouble(double v) | 寫入double 值 |
void writeBoolean(boolean v) | 寫入boolean 類型的值 |
void writeChar(int v) | 寫入char 類型的值, 可以直接寫入單箇中文字符。 可寫入 \t 和\n |
void writeChars(String s) | 寫入字符串 |
void writeUTF(String str) | 使用機器無關的方式使用 modified UTF-8編碼將字符串寫入底層輸出流。 |
void writeObject(Object obj) | 寫入對象 |
對於 ObjectOutputStream 對象,只需要記住 writeObject() 方法即可。
二.二 演示 ObjectOutputStream
在序列化對象之前, 必須要保證 那個實體類, 即 Person 類,實現了 java.io.Serializable 接口, 否則會拋出異常的。
public class Person implements Serializable {
}
二.二.一 寫入 單個對象
@Test
public void write1Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data2.txt");
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
Person person=new Person(1,"兩個蝴蝶飛",'男',24,"一個快樂的程序員");
//如果沒有序列化,會報錯。
objectOutputStream.writeObject(person);
objectOutputStream.close();
}
運行程序, 查看 data2.txt 文件內容:
大概可以猜測是三部分, 第一部分是 類全限定名稱, 第二部分是屬性, 第三部分是 數據。
二.二.二 寫入集合對象
同樣是 writeObject ()方法處理。
@Test
public void write2Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data3.txt");
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
Person person1=new Person(1,"兩個蝴蝶飛1",'男',24,"一個快樂的程序員1");
Person person2=new Person(2,"兩個蝴蝶飛2",'男',24,"一個快樂的程序員2");
Person person3=new Person(3,"兩個蝴蝶飛3",'男',24,"一個快樂的程序員3");
Person person4=new Person(4,"兩個蝴蝶飛4",'男',24,"一個快樂的程序員4");
Person[] ps=new Person[]{person1,person2,person3,person4};
//如果沒有序列化,會報錯。
objectOutputStream.writeObject(ps);
objectOutputStream.close();
}
運行程序,查看 data3.txt
我們雖然看不懂,但 ObjectInputStream 卻能看懂,能解析。
三. 反序列化 ObjectInputStream
三.一 方法
三.一.一 構造方法
三.一.一.一 方法
方法 | 作用 |
---|---|
ObjectInputStream(InputStream in) | 傳入 inputStream 對象 |
三.一.一.二 演示
@Test
public void readConTest() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data2.txt");
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
}
三.一.二 讀取方法
方法 | 作用 |
---|---|
int readInt() | 讀取 int ,實際上就是讀取4個長度 |
long readLong() | 讀取 long |
float readFloat() | 讀取float |
double readDouble() | 讀取double |
boolean readBoolean() | 讀取boolean |
char readChar() | 讀取char, 實際內部讀取兩個字節 |
String readUTF() | 讀取字符串 |
Object readObject() | 讀取對象 |
對於 ObjectInputStream 對象,只需要記住 readObject() 方法即可。
三.二 演示 ObjectInputStream
三.二.一 讀取序列化的單個對象
@Test
public void read1Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data2.txt");
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
Object obj= objectInputStream.readObject();
//向上轉型
Person person=(Person)obj;
System.out.println("員工:"+person.toString());
objectInputStream.close();
}
運行程序,查看控制檯打印輸出:
三.二.二 讀取序列化的對象集合
@Test
public void read2Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data3.txt");
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
Object readObj= objectInputStream.readObject();
//對象數組
Object[] objs=(Object[])readObj;
for(Object obj:objs){
//對每一個進行強制轉換。
Person person=(Person)obj;
System.out.println("員工:"+person);
}
objectInputStream.close();
}
運行程序,查看控制檯打印輸出:
可以正確的讀取。
四. 序列化部分屬性 transient
有時候,一個實體類中屬性過多,不需要全部保存起來,或者某個屬性太重要,需要保證安全,不能存儲起來, 那麼就需要 使用 transient 關鍵字進行阻止序列化。
如 阻止序列化 name 和 sex
重新運行一下 write2Test() 和 read2Test() 方法,查看控制檯
就發現, name 和 sex 沒有被序列化。
五. Externalizable 接口實現序列化
除了 Serializable 接口可以實現序列化外,還可以使用 java.io.Externalizable 接口 進行序列化, 但常用的還是 Serializable 接口, 這個接口 Externalizable 只需要瞭解即可。
package java.io;
import java.io.ObjectOutput;
import java.io.ObjectInput;
/**
* @since JDK1.1
*/
public interface Externalizable extends java.io.Serializable {
void writeExternal(ObjectOutput out) throws IOException;
void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}
writeExternal() 方法 設置的是 保存哪些屬性,
readExternal() 方法,設置的是讀取哪些屬性。
注意,保存和讀取屬性的順序 必須保持一致。
五.一 Externalizable 實現序列化
五.一.一 實體類 實現 接口
public class Person2 implements Externalizable {
}
五.一.二 重寫 writeExternal() 方法,設置保存的屬性
@Override
public void writeExternal(ObjectOutput out) throws IOException {
//保存哪些, 保存的數據。
out.writeInt(id);
out.writeObject(name);
//不保存 sex 屬性
out.writeInt(age);
out.writeObject(desc);
}
五.一.三 重寫 readExternal() 方法,讀取保存的屬性
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//讀取的, 按照保存的順序讀取
this.id=in.readInt();
this.name=(String)in.readObject();
this.age=in.readInt();
this.desc=(String)in.readObject();
}
五.一.四 序列化單個對象
@Test
public void write1Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data4.txt");
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream(file));
Person2 Person2=new Person2(1,"兩個蝴蝶飛",'男',24,"一個快樂的程序員");
//如果沒有序列化,會報錯。
objectOutputStream.writeObject(Person2);
objectOutputStream.close();
}
與 以前的方法是一樣的。
運行程序,查看 data4.txt 的內容。
五.一.五 反序列化單個對象
@Test
public void read1Test() throws Exception{
File file=new File("E:"+ File.separator+"ideaWork"+File.separator+"Java2"+File.separator+"fileSrc"
+File.separator+"data4.txt");
ObjectInputStream objectInputStream=new ObjectInputStream(new FileInputStream(file));
Object obj= objectInputStream.readObject();
Person2 Person2=(Person2)obj;
System.out.println("員工:"+Person2);
objectInputStream.close();
}
運行程序:
對象集合的序列化和反序列化與以前的也是一樣的,就不重複寫了。
五.二 Serializable 和 Externalizable 的區別
區別 | Serializable | Externalizable |
---|---|---|
實現上 | 實現簡單,Java提供了支持 | 實現複雜,需要開發人員寫保存和讀取 |
執行效率上 | 由Java統一 保存,性能較低 | 開發人員決定,速度可能會高 |
保存信息所佔空間 | 空間大 | 空間較小 |
開發中,常使用的是 Serializable
序列化非常重要,一定要掌握。
謝謝您的觀看,如果喜歡,請關注我,再次感謝 !!!