亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

存取程序狀態的幾種方法--Java I/O應用雜談

系統 2511 0

文件I/O:文件流→序列化


文件流
文件操作是最簡單最直接也是最容易想到的一種方式,我們說的文件操作不僅僅是通過FileInputStream/FileOutputStream這么“裸”的方式直接把數據寫入到本地文件(像我以前寫的一個掃雷的小游戲JavaMine就是這樣保存一局的狀態的),這樣就比較“底層”了。

主要類與方法和描述
  1. FileInputStream.read() //從本地文件讀取二進制格式的數據
  2. FileReader.read() //從本地文件讀取字符(文本)數據
  3. FileOutputStream.write() //保存二進制數據到本地文件
  4. FileWriter.write() //保存字符數據到本地文件

XML
和上面的單純的I/O方式相比,XML就顯得“高檔”得多,以至于成為一種數據交換的標準。以 DOM方式 為例,它關心的是首先 在內存中構造文檔樹 ,數據保存在某個結點上(可以是葉子結點,也可以是標簽結點的屬性),構造好了以后一次性的寫入到外部文件,但我們只需要知道文件的位置,并不知道I/O是怎么操作的,XML操作方式可能多數人也實踐過,所以這里也只列出相關的方法,供初學者預先了解一下。主要的包是 javax.xml.parsers , org.w3c.dom javax.xml.transform

主要類與方法和描述
  1. DocumentBuilderFactory.newDocumentBuilder().parse() //解析一個外部的XML文件,得到一個Document對象的DOM樹
  2. DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument() //初始化一棵DOM樹
  3. Document.getDocumentElement().appendChild() //為一個標簽結點添加一個子結點
  4. Document.createTextNode() //生成一個字符串結點
  5. Node.getChildNodes() //取得某個結點的所有下一層子結點
  6. Node.removeChild() //刪除某個結點的子結點
  7. Document.getElementsByTagName()查找所有指定名稱的標簽結點
  8. Document.getElementById() //查找指定名稱的一個標簽結點,如果有多個符合,則返回某一個,通常是第一個
  9. Element.getAttribute() //取得一個標簽的某個屬性的的值
  10. Element.setAttribute() //設置一個標簽的某個屬性的的值
  11. Element.removeAttribute() //刪除一個標簽的某個屬性
  12. TransformerFactory.newInstance().newTransformer().transform() //將一棵DOM樹寫入到外部XML文件

序列化
使用基本的文件讀寫方式存取數據,如果我們僅僅保存 相同類型 的數據,則可以用同一種格式保存,譬如在我的JavaMine中保存一個盤局時,需要保存每一個方格的坐標、是否有地雷,是否被翻開等,這些信息組合成一個“復合類型”;相反,如果有多種 不同類型 的數據,那我們要么把它分解成若干部分,以相同類型(譬如String)保存,要么我們需要在程序中添加解析不同類型數據格式的邏輯,這就很不方便。于是我們期望用一種比較“高”的層次上處理數據,程序員應該 花盡可能少的時間和代碼對數據進行解析 ,事實上,序列化操作為我們提供了這樣一條途徑。
序列化(Serialization)大家可能都有所接觸,它可以把對象以某種特定的編碼格式寫入或從外部字節流(即 ObjectInputStream / ObjectOutputStream )中讀取。序列化一個對象非常之簡單,僅僅實現一下Serializable接口即可,甚至都不用為它專門添加任何方法:
  1. public class MySerial implements java.io. Serializable
  2. {
  3. //...
  4. }

但有一個條件:即 你要序列化的類當中,它的每個屬性都必須是是“可序列化”的 。這句話說起來有點拗口,其實所有 基本類型 (就是int,char,boolean之類的) 都是“可序列化”的 ,而你可以看看JDK文檔,會發現很多類其實已經實現了Serializable(即已經是“可序列化”的了),于是這些類的對象以及基本數據類型都可以直接作為你需要序列化的那個類的內部屬性。如果碰到了不是“可序列化”的屬性怎么辦?對不起,那這個屬性的類還需要事先實現Serializable接口,如此遞歸, 直到所有屬性都是“可序列化”的 。

主要類與方法和描述
  1. ObjectOutputStream.writeObject() //將一個對象序列化到外部字節流
  2. ObjectInputStream.readObject() //從外部字節流讀取并重新構造對象

從實際應用上看來,“Serializable”這個接口并沒有定義任何方法,仿佛它只是一個標記(或者說像是Java的關鍵字)而已,一旦虛擬機看到這個“ 標記 ”,就會嘗試調用自身 預定義的序列化機制 ,除非你在實現Serializable接口的同時還定義了私有的readObject()或writeObject()方法。這一點很奇怪。不過你要是不愿意讓系統使用缺省的方式進行序列化,那就必須定義上面提到的兩個方法:
  1. public class MySerial implements java.io. Serializable
  2. {
  3. private void writeObject(java.io. ObjectOutputStream out) throws IOException
  4. {
  5. //...
  6. }
  7. private void readObject(java.io. ObjectInputStream in) throws IOException, ClassNotFoundException
  8. {
  9. //...
  10. }
  11. //...
  12. }

譬如你可以在上面的writeObject()里調用默認的序列化方法ObjectOutputStream. defaultWriteObject ();譬如你不愿意將某些敏感的屬性和信息序列化,你也可以調用ObjectOutputStream.writeObject()方法明確指定需要序列化那些屬性。關于用戶可定制的序列化方法,我們將在后面提到。

Bean
上面的序列化只是一種基本應用,你把一個對象序列化到外部文件以后,用notepad打開那個文件,只能從為數不多的一些可讀字符中猜到這是有關這個類的信息文件,這需要你熟悉序列化文件的字節編碼方式,那將是比較痛苦的(在 《CoreJava2》第一卷 里提到了相關編碼方式,有興趣的話可以查看參考資料),某些情況下我們可能需要被序列化的文件具有更好的可讀性。另一方面,作為Java組件的核心概念“ JavaBeans ”,從JDK1.4開始,其規范里也要求支持文本方式的“ 長期的持久化 ”(long-termpersistence)。
打開 JDK文檔 , java.beans包 里的有一個名為“ Encoder ”的類,這就是一個可以序列化bean的實用類。和它相關的兩個主要類有 XMLEcoder XMLDecoder ,顯然,這是以XML文件的格式保存和讀取bean的工具。他們的用法也很簡單,和上面ObjectOutputStream/ObjectInputStream比較類似。

主要類與方法和描述
  1. XMLEncoder.writeObject() //將一個對象序列化到外部字節流
  2. XMLDecoder.readObject() //從外部字節流讀取并重新構造對象

如果一個bean是如下格式:
  1. public class MyBean
  2. {
  3. int i;
  4. char []c;
  5. String s;
  6. //...(get和set操作省略)...
  7. }

那么通過XMLEcoder序列化出來的XML文件具有這樣的形式:

<?xmlversion="1.0"encoding="UTF-8"?>
<javaversion="1.4.0"class="java.beans.XMLDecoder">
<objectclass="MyBean">
<voidproperty="i">
<int>1</int>
</void>
<voidproperty="c">
<arrayclass="char"length="3">
<voidindex="0">
<int>a</int>
</void>
<voidindex="1">
<int>b</int>
</void>
<voidindex="2">
<int>c</int>
</void>
</array>
</void>
<voidproperty="s">
<string>foxjump!</string>
</void>
</object>
</java>

AWT Swing 中很多可視化組件都是bean,當然也是可以用這種方式序列化的,下面就是從JDK文檔中摘錄的一個 JFrame 序列化以后的XML文件:

<?xmlversion="1.0"encoding="UTF-8"?>
<javaversion="1.0"class="java.beans.XMLDecoder">
<objectclass="javax.swing.JFrame">
<voidproperty="name">
<string>frame1</string>
</void>
<voidproperty="bounds">
<objectclass="java.awt.Rectangle">
<int>0</int>
<int>0</int>
<int>200</int>
<int>200</int>
</object>
</void>
<voidproperty="contentPane">
<voidmethod="add">
<objectclass="javax.swing.JButton">
<voidproperty="label">
<string>Hello</string>
</void>
</object>
</void>
</void>
<voidproperty="visible">
<boolean>true</boolean>
</void>
</object>
</java>

因此但你想要保存的數據是一些不是太復雜的類型的話,把它做成bean再序列化也不失為一種方便的選擇。

Properties
在以前我總結的一篇關于集合框架的小文章里提到過, Properties 是歷史集合類的一個典型的例子,這里主要不是介紹它的集合特性。大家可能都經常接觸一些 配置文件 ,如Windows的ini文件,Apache的conf文件,還有Java里的properties文件等,這些文件當中的數據以 “關鍵字-值”對 的方式保存?!? 環境變量 ”這個概念都知道吧,它也是一種“key-value”對,以前也常常看到版上問“如何取得系統某某信息”之類的問題,其實很多都保存在環境變量里,只要用一條
  1. System .getProperties().list( System .out);

就能獲得全部環境變量的列表:

--listingproperties--
java.runtime.name=Java(TM)2RuntimeEnvironment,Stand...
sun.boot.library.path=C:/ProgramFiles/Java/j2re1.4.2_05/bin
java.vm.version=1.4.2_05-b04
java.vm.vendor=SunMicrosystemsInc.
java.vendor.url=http://java.sun.com/
path.separator=;
java.vm.name=JavaHotSpot(TM)ClientVM
file.encoding.pkg=sun.io
user.country=CN
sun.os.patch.level=ServicePack1
java.vm.specification.name=JavaVirtualMachineSpecification
user.dir=d:/mydocuments/項目/eclipse/SWTDemo
java.runtime.version=1.4.2_05-b04
java.awt.graphicsenv=sun.awt.Win32GraphicsEnvironment
java.endorsed.dirs=C:/ProgramFiles/Java/j2re1.4.2_05/li...
os.arch=x86
java.io.tmpdir=C:/DOCUME~1/cn2lx0q0/LOCALS~1/Temp/
line.separator=

java.vm.specification.vendor=SunMicrosystemsInc.
user.variant=
os.name=WindowsXP
sun.java2d.fontpath=
java.library.path=C:/ProgramFiles/Java/j2re1.4.2_05/bi...
java.specification.name=JavaPlatformAPISpecification
java.class.version=48.0
java.util.prefs.PreferencesFactory=java.util.prefs.WindowsPreferencesFac...
os.version=5.1
user.home=D:/Users/cn2lx0q0
user.timezone=
java.awt.printerjob=sun.awt.windows.WPrinterJob
file.encoding=GBK
java.specification.version=1.4
user.name=cn2lx0q0
java.class.path=d:/mydocuments/項目/eclipse/SWTDemo/bi...
java.vm.specification.version=1.0
sun.arch.data.model=32
java.home=C:/ProgramFiles/Java/j2re1.4.2_05
java.specification.vendor=SunMicrosystemsInc.
user.language=zh
awt.toolkit=sun.awt.windows.WToolkit
java.vm.info=mixedmode
java.version=1.4.2_05
java.ext.dirs=C:/ProgramFiles/Java/j2re1.4.2_05/li...
sun.boot.class.path=C:/ProgramFiles/Java/j2re1.4.2_05/li...
java.vendor=SunMicrosystemsInc.
file.separator=/
java.vendor.url.bug=http://java.sun.com/cgi-bin/bugreport...
sun.cpu.endian=little
sun.io.unicode.encoding=UnicodeLittle
sun.cpu.isalist=pentiumi486i386


主要類與方法和描述
  1. load() //從一個外部流讀取屬性
  2. store() //將屬性保存到外部流(特別是文件)
  3. getProperty() //取得一個指定的屬性
  4. setProperty() //設置一個指定的屬性
  5. list() //列出這個Properties對象包含的全部“key-value”對
  6. System .getProperties() //取得系統當前的環境變量


你可以這樣保存一個properties文件:

  1. Propertiesprop= new Properties();
  2. prop.setProperty("key1","value1");
  3. ...
  4. FileOutputStreamout= new FileOutputStream("config.properties");
  5. prop.store(out,"--這里是文件頭,可以加入注釋--");

Preferences
如果我說Java里面可以不使用JNI的手段操作Windows的注冊表你信不信?很多軟件的菜單里都有“Setting”或“Preferences”這樣的選項用來設定或修改軟件的配置,這些配置信息可以保存到一個像上面所述的配置文件當中,如果是Windows平臺下,也可能會保存到系統注冊表中。從JDK1.4開始,Java在 java.util 下加入了一個專門處理用戶和系統配置信息的 java.util.prefs 包,其中一個類 Preferences 是一種比較“高級”的玩意。從本質上講,Preferences本身是一個與平臺無關的東西,但不同的OS對它的SPI(ServiceProviderInterface)的實現卻是與平臺相關的,因此,在不同的系統中你可能看到首選項保存為本地文件、LDAP目錄項、數據庫條目等,像在Windows平臺下,它就保存到了系統注冊表中。不僅如此,你還可以把首選項導出為XML文件或從XML文件導入。

主要類與方法和描述
  1. systemNodeForPackage() //根據指定的Class對象得到一個Preferences對象,這個對象的注冊表路徑是從“HKEY_LOCAL_MACHINE/”開始的
  2. systemRoot() //得到以注冊表路徑HKEY_LOCAL_MACHINE/SOFTWARE/Javasoft/Prefs為根結點的Preferences對象
  3. userNodeForPackage() //根據指定的Class對象得到一個Preferences對象,這個對象的注冊表路徑是從“HKEY_CURRENT_USER/”開始的
  4. userRoot() //得到以注冊表路徑HKEY_CURRENT_USER/SOFTWARE/Javasoft/Prefs為根結點的Preferences對象
  5. putXXX() //設置一個屬性的值,這里XXX可以為基本數值型類型,如int、long等,但首字母大寫,表示參數為相應的類型,也可以不寫而直接用put,參數則為字符串
  6. getXXX() //得到一個屬性的值
  7. exportNode() //將全部首選項導出為一個XML文件
  8. exportSubtree() //將部分首選項導出為一個XML文件
  9. importPreferences() //從XML文件導入首選項

你可以按如下步驟保存數據:
  1. PreferencesmyPrefs1=Preferences.userNodeForPackage( this ); //這種方法是在“HKEY_CURRENT_USER/”下按當前類的路徑建立一個注冊表項
  2. PreferencesmyPrefs2=Preferences.systemNodeForPackage( this ); //這種方法是在“HKEY_LOCAL_MACHINE/”下按當前類的路徑建立一個注冊表項
  3. PreferencesmyPrefs3=Preferences.userRoot().node("com.jungleford.demo"); //這種方法是在“HKEY_CURRENT_USER/SOFTWARE/Javasoft/Prefs/”下按“com/jungleford/demo”的路徑建立一個注冊表項
  4. PreferencesmyPrefs4=Preferences.systemRoot().node("com.jungleford.demo"); //這種方法是在“HKEY_LOCAL_MACHINE/SOFTWARE/Javasoft/Prefs/”下按“com/jungleford/demo”的路徑建立一個注冊表項
  5. myPrefs1.putInt("key1",10);
  6. myPrefs1.putDouble("key2",-7.15);
  7. myPrefs1.put("key3","value3");
  8. FileOutputStreamout= new FileOutputStream("prefs.xml");
  9. myPrefs1.exportNode(out);

網絡I/O:Socket→RMI


Socket
Socket編程可能大家都很熟,所以就不多討論了,只是說通過socket把數據保存到遠端服務器或從網絡socket讀取數據也不失為一種值得考慮的方式。

RMI
RMI機制其實就是RPC(遠程過程調用)的Java版本,它使用socket作為基本傳輸手段,同時也是序列化最重要的一個應用?,F在網絡傳輸從編程的角度來看基本上都是 以流的方式 操作,socket就是一個例子,將對象轉換成字節流的一個重要目標就是為了方便網絡傳輸。
想象一下傳統的 單機環境 下的程序設計,對于Java語言的函數(方法)調用(注意與C語言函數調用的區別)的參數傳遞,會有兩種情況:如果是 基本數據類型 ,這種情況下和C語言是一樣的,采用 值傳遞 方式;如果是 對象 ,則傳遞的是對象的 引用 ,包括返回值也是引用,而不是一個完整的對象拷貝!試想一下在 不同的虛擬機 之間進行方法調用,即使是兩個完全同名同類型的對象他們也很可能是不同的引用!此外對于方法調用過程,由于被調用過程的壓棧,內存“現場”完全被被調用者占有,當被調用方法返回時,才將調用者的地址寫回到程序計數器(PC),恢復調用者的狀態,如果是兩個虛擬機,根本不可能用簡單壓棧的方式來保存調用者的狀態。因為種種原因,我們才需要建立RMI通信實體之間的“代理”對象,譬如“存根”就相當于遠程服務器對象在客戶機上的代理,stub就是這么來的,當然這是后話了。
本地對象與遠程對象(未必是物理位置上的不同機器,只要不是在同一個虛擬機內皆為“遠程”)之間傳遞參數和返回值,可能有這么幾種情形:
  • 值傳遞:這又包括兩種子情形:如果是基本數據類型,那么都是“可序列化”的,統統序列化成可傳輸的字節流;如果是對象,而且不是“遠程對象”(所謂“遠程對象”是實現了java.rmi.Remote接口的對象),本來對象傳遞的應該是引用,但由于上述原因,引用是不足以證明對象身份的,所以傳遞的仍然是 一個序列化的拷貝 (當然這個對象也必須滿足上述“可序列化”的條件)。
  • 引用傳遞:可以引用傳遞的只能是“遠程對象”。這里所謂的“引用”不要理解成了真的只是一個符號,它其實是一個留在(客戶機)本地stub中的,和遠端服務器上那個真實的對象張得一模一樣的 鏡像 而已!只是因為它有點“特權”(不需要經過序列化),在本地內存里已經有了一個實例,真正引用的其實是這個“孿生子”。

由此可見,序列化在RMI當中占有多么重要的地位。

數據庫I/O:CMP、Hibernate


什么是“Persistence”
用過VMWare的朋友大概都知道當一個guestOS正在運行的時候點擊“Suspend”將虛擬OS掛起,它會把整個虛擬內存的內容保存到磁盤上,譬如你為虛擬OS分配了128M的運行內存,那掛起以后你會在虛擬OS所在的目錄下找到一個同樣是128M的文件,這就是虛擬OS內存的完整鏡像!這種內存的鏡像手段其實就是“Persistence”(持久化)概念的由來。

CMP和Hibernate
因為我對J2EE的東西不是太熟悉,隨便找了點材料看看,所以擔心說的不到位,這次就不作具體總結了,人要學習……真是一件痛苦的事情

序列化再探討


從以上技術的討論中我們不難體會到,序列化是Java之所以能夠出色地實現其鼓吹的兩大賣點??分布式(distributed)和跨平臺(OSindependent)的一個重要基礎。TIJ(即“ ThinkinginJava ”)談到I/O系統時,把序列化稱為“lightweightpersistence”??“輕量級的持久化”,這確實很有意思。

為什么叫做“序列”化?
開場白里我說更習慣于把“Serialization”稱為“序列化”而不是“串行化”,這是有原因的。介紹這個原因之前先回顧一些計算機基本的知識,我們知道現代計算機的內存空間都是 線性編址 的(什么是“線性”知道吧,就是一個元素只有一個唯一的“前驅”和唯一的“后繼”,當然頭尾元素是個例外;對于地址來說,它的下一個地址當然不可能有兩個,否則就亂套了),“地址”這個概念推廣到數據結構,就相當于“指針”,這個在本科低年級大概就知道了。注意了,既然是線性的,那“地址”就可以看作是內存空間的“序號”,說明它的組織是有順序的,“ 序號 ”或者說“序列號”正是“Serialization”機制的一種體現。為什么這么說呢?譬如我們有兩個對象a和b,分別是類A和B的實例,它們都是可序列化的,而A和B都有一個類型為C的屬性,根據前面我們說過的原則,C當然也必須是可序列化的。
  1. import java.io.*;
  2. ...
  3. class A implements Serializable
  4. {
  5. Cc;
  6. ...
  7. }
  8. class B implements Serializable
  9. {
  10. Cc;
  11. ...
  12. }
  13. class C implements Serializable
  14. {
  15. ...
  16. }
  17. Aa;
  18. Bb;
  19. Cc1;
  20. ...

注意,這里我們在實例化a和b的時候,有意讓他們的c屬性使用同一個C類型對象的引用,譬如c1,那么請試想一下,但我們序列化a和b的時候,它們的c屬性在外部字節流(當然可以不僅僅是文件)里保存的是一份拷貝還是兩份拷貝呢?序列化在這里使用的是一種 類似于“指針”的方案 :它為每個被序列化的對象標上一個“ 序列號 ”(serialnumber),但序列化一個對象的時候,如果其某個屬性對象是已經被序列化的,那么這里只向輸出流寫入該屬性的序列號;從字節流恢復被序列化的對象時,也根據序列號找到對應的流來恢復。這就是“序列化”名稱的由來!這里我們看到“序列化”和“指針”是極相似的,只不過“指針”是內存空間的地址鏈,而序列化用的是 外部流中的“序列號鏈” 。
使用“序列號”而不是內存地址來標識一個被序列化的對象,是因為從流中恢復對象到內存,其地址可能就未必是原來的地址了??我們需要的只是這些對象之間的引用關系,而不是死板的原始位置,這在RMI中就更是必要,在兩臺不同的機器之間傳遞對象(流),根本就不可能指望它們在兩臺機器上都具有相同的內存地址。

更靈活的“序列化”:transient屬性和Externalizable
Serializable確實很方便,方便到你幾乎不需要做任何額外的工作就可以輕松將內存中的對象保存到外部。但有兩個問題使得Serializable的威力收到束縛:
一個是效率問題,《CoreJava2》中指出,Serializable使用系統默認的序列化機制會影響軟件的運行速度,因為需要為每個屬性的引用編號和查號,再加上I/O操作的時間(I/O和內存讀寫差的可是一個數量級的大小),其代價當然是可觀的。
另一個困擾是“裸”的Serializable 不可定制 ,傻乎乎地什么都給你序列化了,不管你是不是想這么做。其實你可以有至少三種定制序列化的選擇。其中一種前面已經提到了,就是在implementsSerializable的類里面添加私有的writeObject()和readObject()方法(這種Serializable就不裸了, ),在這兩個方法里,該序列化什么,不該序列化什么,那就由你說了算了,你當然可以在這兩個方法體里面分別調用ObjectOutputStream. defaultWriteObject ()和ObjectInputStream. defaultReadObject ()仍然執行 默認的序列化動作 (那你在代碼上不就做無用功了?呵呵),也可以用ObjectOutputStream.writeObject()和ObjectInputStream.readObject()方法對你中意的屬性進行序列化。但虛擬機一看到你定義了這兩個方法,它就不再用默認的機制了。
如果僅僅為了跳過某些屬性不讓它序列化,上面的動作似乎顯得麻煩,更簡單的方法是對不想序列化的屬性加上 transient 關鍵字,說明它是個“暫態變量”,默認序列化的時候就不會把這些屬性也塞到外部流里了。當然,你如果定義writeObject()和readObject()方法的化,仍然可以把暫態變量進行序列化。題外話,像 transient 、 violate 、 finally 這樣的關鍵字初學者可能會不太重視,而現在有的公司招聘就偏偏喜歡問這樣的問題:(
再一個方案就是不實現Serializable而改成實現 Externalizable 接口。我們研究一下這兩個接口的源代碼,發現它們很類似,甚至容易混淆。我們要記住的是:Externalizable默認并 不保存任何對象相關信息 !任何保存和恢復對象的動作都是你自己定義的。Externalizable包含兩個public的方法:
  1. public void writeExternal(ObjectOutputout) throws IOException;
  2. public void readExternal(ObjectInputin) throws IOException, ClassNotFoundException ;

乍一看這和上面的writeObject()和readObject()幾乎差不多,但Serializable和Externalizable走的是兩個不同的流程:Serializable在對象不存在的情況下,就可以僅憑外部的字節序列把整個對象重建出來;但Externalizable在重建對象時,先是調用該類的默認構造函數(即不含參數的那個構造函數)使得內存中先有這么一個實例,然后再調用readExternal方法對實例中的屬性進行恢復,因此,如果默認構造函數中和readExternal方法中都沒有賦值的那些屬性,特別他們是非基本類型的話,將會是空(null)。在這里需要注意的是, transient只能用在對Serializable而不是Externalizable的實現里面 。

序列化與克隆
從“可序列化”的遞歸定義來看,一個序列化的對象貌似對象內存映象的外部克隆,如果沒有共享引用的屬性的化,那么應該是一個 深度克隆 。關于克隆的話題有可以談很多,這里就不細說了,有興趣的話可以參考 IBMdeveloperWorks 上的一篇文章: JAVA中的指針,引用及對象的clone

一點啟示


作為一個實際的應用,我在寫那個簡易的郵件客戶端JExp的時候曾經對比過好幾種保存Message對象(主要是幾個關鍵屬性和郵件的內容)到本地的方法,譬如XML、Properties等,最后還是選擇了用序列化的方式,因為這種方法最簡單,大約可算是“學以致用”罷。這里“存取程序狀態”其實只是一個引子話題罷了,我想說的是??就如同前面我們討論的關于logging的話題一樣??在Java面前對同一個問題你可以有很多種solution:熟悉文件操作的,你可能會覺得Properties、XML或Bean比較方便,然后又發現了還有Preferences這么一個東東,大概又會感慨“天外有天”了,等到你接觸了很多種新方法以后,結果又會“殊途同歸”,重新反省Serialization機制本身。這不僅是Java,科學也是同樣的道理。

存取程序狀態的幾種方法--Java I/O應用雜談


更多文章、技術交流、商務合作、聯系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦?。。?/p>

發表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 成人在线播放 | 四虎成人精品在永久在线观看 | 日本免费新一区二区三区 | 久久久久久午夜精品 | 国产成人精品亚洲日本在线 | 69美女福利视频在线观看 | 99热国产这里只有精品免费 | 久久综合久色欧美婷婷 | 免费一级毛片在线视频观看 | 日韩高清一区二区三区不卡 | 老司机激情影院 | 日韩性大片免费 | 国产大片91精品免费观看不卡 | 日韩毛片久久91 | 国产国语一级毛片中文 | 日韩精品久久不卡中文字幕 | 国产精品亚洲精品爽爽 | videosex久久麻豆 | 国产欧美日韩高清专区手机版 | 毛片视频网站在线观看 | 国产高清亚洲 | 欧美不卡精品中文字幕日韩 | 成人毛片免费看 | 中文字幕中韩乱码亚洲大片 | 亚洲精品久久久久久下一站 | 国产乱在线观看视频 | 亚洲伊人精品综合在合线 | 天天做夜夜做久久做狠狠 | 日韩 欧美 中文 | 成人看黄色大片 | 久久99国产这里有精品视 | 国产精品视频第一区二区 | 国产一区中文字幕在线观看 | 欧美人成一本免费观看视频 | 天天色综合色 | 特级毛片在线观看 | 中国美女一级毛片 | 亚洲视频二 | 激情一区二区三区成人 | 伊人不卡久久大香线蕉综合影院 | 一级片短视频 |