JavaSE——IO(下)(Properties类、序列化与反序列化)
第3節(jié) IO(下)
一、.properties文件與Properties類
1.1 .properties文件介紹
.properties文件一種屬性文件,以鍵值對 的格式存儲內(nèi)容,在Java中可以使用Properties類來讀取這個文件,一般來說它作為一些參數(shù)的存儲,作為配置文件使用。
1.2 Properties類
它是Hashtable的子類,使用鍵值對來存儲數(shù)據(jù)。
構(gòu)造方法:
方法:
1、根據(jù)鍵獲取值:
2、將鍵值對打印到指定的輸出流:
3、從輸入字節(jié)流或字符流中讀取全部內(nèi)容:
4、返回所有鍵的枚舉:
5、新增鍵值對:
6、存儲到字節(jié)輸出流或字符輸出流,comment是備注,寫在存儲文件的開頭:
7、返回所有的值,以Set類型:
看個例子:
package com.kaikeba.coreclasslibrary.io;import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.util.Properties;public class properties {public static void main(String[] args) throws IOException {//.properties文件與Properties類//新建一個Properties對象Properties ppt = new Properties();//新建鍵值對ppt.setProperty("name","三體");ppt.setProperty("info","科幻小說");//要寫入的字符流FileWriter fw = new FileWriter("book.properties");//往fw中存儲該鍵值對集合的對象,備注為"存儲的圖書"ppt.store(fw, "存儲的圖書");fw.close();//從.properties文件讀取屬性Properties ppt2 = new Properties();Reader r = new FileReader("book.properties");ppt2.load(r);System.out.println(ppt.get("name"));System.out.println(ppt.get("info"));} }輸出為: 三體 科幻小說且book.properties文件中存儲的內(nèi)容為:
最上面是備注信息,使用了Unicode編碼。
二、序列化與反序列化
Java序列化是指把java對象轉(zhuǎn)換為字節(jié)序列的過程 ,Java反序列化是指把字節(jié)序列恢復為java對象的過程 。通過序列化和反序列化實現(xiàn)網(wǎng)絡傳輸、本地存儲的目的 。
2.1 Serializable實現(xiàn)Java序列化
要實現(xiàn)java對象的序列化,只要將類實現(xiàn)標識接口 ——Serializable接口即可,不需要我們重寫任何方法就可以實現(xiàn)序列化。
編寫書籍類:
package com.kaikeba.coreclasslibrary.io.serializable;import java.io.Serializable;public class Book implements Serializable {private String name;private String info;private Person user;@Overridepublic String toString() {return "Book{" +"name='" + name + '\'' +", info='" + info + '\'' +", user=" + user +'}';}public Book() {}public Book(String name, String info, Person user) {this.name = name;this.info = info;this.user = user;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}public Person getUser() {return user;}public void setUser(Person user) {this.user = user;} }編寫借書人類:注意Book中有Person類的對象屬性,所以Person類也要實現(xiàn)Serializable接口
package com.kaikeba.coreclasslibrary.io.serializable;import java.io.Serializable;public class Person implements Serializable {private String name;private int age;@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';}public Person() {}public Person(String name, int age) {this.name = name;this.age = age;}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;} }編寫序列化和反序列化:
package com.kaikeba.coreclasslibrary.io.serializable;import java.io.*;public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {//序列化Person p = new Person("smile", 23);Book b = new Book("三體", "科幻小說", p);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("b.txt"));oos.writeObject(b);oos.close();//反序列化ObjectInputStream ois = new ObjectInputStream(new FileInputStream("b.txt"));Book book = (Book) ois.readObject();System.out.println(book);} }結(jié)果如下:
原始對象: Book{name='三體', info='科幻小說', user=Person{name='smile', age=23}} 反序列化之后的對象: Book{name='三體', info='科幻小說', user=Person{name='smile', age=23}}主要是使用到了ObjectOutputStream和ObjectInputStream類,ObjectOutputStream類使用writeObject將對象寫到文件中,ObjectInputStream類使用readObject將對象從文件中讀取出來。
2.2 部分屬性的序列化
實現(xiàn)部分字段序列化的方式:
-
使用transient修飾符
-
使用static修飾符
-
默認方法writeObject和readObject
-
Externalizable實現(xiàn)
2.2.1 使用transient修飾符
修改實體類,將實體類中不想被序列化的屬性添加transient修飾符。
public class Book implements Serializable {private String name;private transient String info;private Person user;... public class Person implements Serializable {private String name;private transient int age; ...結(jié)果如下:
原始對象: Book{name='三體', info='科幻小說', user=Person{name='smile', age=23}} 反序列化之后的對象: Book{name='三體', info='null', user=Person{name='smile', age=0}}用transient修飾的屬性都沒有被序列化,因此反序列化的結(jié)果也是默認值。
2.2.2 使用static修飾符
static修飾符修飾的屬性會參與序列化,但是如果在反序列化的時候?qū)ζ溥M行重新賦值,反序列化后的結(jié)果會隨之改變:
public class Book implements Serializable {private String name;private static String info;private Person user;...public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {//序列化Person p = new Person("smile", 23);Book b = new Book("三體", "科幻小說", p);System.out.println("原始對象:\n"+b);ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("b.txt"));oos.writeObject(b);oos.close();//反序列化b.setInfo("中國最牛的科幻小說");ObjectInputStream ois = new ObjectInputStream(new FileInputStream("b.txt"));Book book = (Book) ois.readObject();System.out.println("反序列化之后的對象:\n"+book);} }結(jié)果:
原始對象: Book{name='三體', info='科幻小說', user=Person{name='smile', age=23}} 反序列化之后的對象: Book{name='三體', info='中國最牛的科幻小說', user=Person{name='smile', age=23}}解釋:其實就是靜態(tài)屬性被修改之后,因為所有對象都是用的同一個內(nèi)容,所以反序列化的靜態(tài)屬性也就變了。
2.2.3 默認方法writeObject和readObject
在Book中添加兩個方法: public class Book implements Serializable {private String name;private String info;private Person user;private void writeObject(ObjectOutputStream oos) throws IOException {System.out.println("writeObject---------------");oos.writeObject(name);oos.writeObject(user);}private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {System.out.println("readObject----------------");name = (String) ois.readObject();user = (Person) ois.readObject();}...結(jié)果為:
原始對象: Book{name='三體', info='科幻小說', user=Person{name='smile', age=23}} writeObject--------------- readObject---------------- 反序列化之后的對象: Book{name='三體', info='null', user=Person{name='smile', age=23}}info屬性沒有寫入兩個函數(shù)中,就沒有被序列化。
源碼分析:
注意:添加的兩個方法必須是private void修飾的,否則不生效。
首先看一下Serializable接口的描述:
ObjectStreamClass類:在序列化(反序列化)的時候,ObjectOutputStream(ObjectInputStream)會尋找目標類中私有的writeObject(readObject)方法,賦值給變量writeObjectMethod(readObjectMethod)。
通過上面這段代碼可以知道,如果writeObjectMethod ≠ null(目標類中定義了私有的writeObject方法),那么將調(diào)用目標類中的writeObject方法,如果writeObject == null,那么將調(diào)用默認的defaultWriteMethod方法來讀取目標類中的屬性。
readObject的調(diào)用邏輯和WriteObject一樣。
總結(jié)一下,如果目標類中沒有定義私有的writeObject或readObject方法,那么序列化和反序列化的時候講調(diào)用默認的方法來根據(jù)目標類中的屬性來進行序列化和反序列化,而如果目標類中定義了私有的writeObject或readObject方法,那么序列化和反序列化的時候講調(diào)用目標類指定的writeObject或readObject方法來實現(xiàn)。
2.3 Externalizable實現(xiàn)java序列化
實現(xiàn)部分屬性序列化的方式的第四種,通過Externalizable接口。
Externalizable繼承自Serializable接口,使用Externalizable接口需要實現(xiàn)readExternal方法和writeExternal方法來實現(xiàn)序列化和反序列化。
Externalizable接口繼承自Serializable接口,所以實現(xiàn)Externalizable接口也能實現(xiàn)序列化和反序列化。Externalizable接口中定義了writeExternal和readExternal兩個抽象方法,這兩個方法其實對應Serializable接口的writeObject和readObject方法,可以這樣理解:Externalizable接口被設計出來的目的就是為了抽象出writeObject和readObject這兩個方法,但是目前這個接口使用的并不多。
三、Serializable vs Externalizable
| 實現(xiàn)復雜度 | 實現(xiàn)簡單,java對其有內(nèi)建支持 | 實現(xiàn)復雜,由開發(fā)人員自己完成 |
| 執(zhí)行效率 | 所有對象由java統(tǒng)一保存,性能較低 | 開發(fā)人員決定哪個對象保存,可能造成速度提升 |
| 保存信息 | 保存時占用空間大 | 部分存儲,可能造成空間減少 |
| 使用頻率 | 高 | 偏低 |
總結(jié)
以上是生活随笔為你收集整理的JavaSE——IO(下)(Properties类、序列化与反序列化)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: OpenCV学习笔记(十七):图像修补:
- 下一篇: pytorch两种常用的学习率衰减方法