国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 學院 > 開發設計 > 正文

Java 理論與實踐:變還是不變?

2019-11-18 14:41:48
字體:
來源:轉載
供稿:網友

  不變對象具有許多能更方便地使用它們的特性,包括不嚴格的同步需求和不必考慮數據訛誤就能自由地共享和高速緩存對象引用。盡管不變性可能未必對于所有類都有意義,但大多數程序中至少有一些類將受益于不可變。在本月的 java 理論與實踐中,Brian Goetz 說明了不變性的一些優點和構造不變類的一些準則。請在附帶的論壇中與作者和其他讀者分享您關于本文的心得。(也可以單擊文章頂部或底部的“討論”來訪問論壇。)
不變對象是指在實例化后其外部可見狀態無法更改的對象。Java 類庫中的 String、Integer 和 BigDecimal 類就是不變對象的示例 — 它們表示在對象的生命期內無法更改的單個值。

不變性的優點
假如正確使用不變類,它們會極大地簡化編程。因為它們只能處于一種狀態,所以只要正確構造了它們,就決不會陷入不一致的狀態。您不必復制或克隆不變對象,就能自由地共享和高速緩存對它們的引用;您可以高速緩存它們的字段或其方法的結果,而不用擔心值會不會變成失效的或與對象的其它狀態不一致。不變類通常產生最好的映射鍵。而且,它們本來就是線程安全的,所以不必在線程間同步對它們的訪問。

自由高速緩存
因為不變對象的值沒有更改的危險,所以可以自由地高速緩存對它們的引用,而且可以肯定以后的引用仍將引用同一個值。同樣地,因為它們的特性無法更改,所以您可以高速緩存它們的字段和其方法的結果。

假如對象是可變的,就必須在存儲對其的引用時引起注重。請考慮清單 1 中的代碼,其中排列了兩個由調度程序執行的任務。目的是:現在啟動第一個任務,而在某一天啟動第二個任務。

清單 1. 可變的 Date 對象的潛在問題 Date d = new Date();
Scheduler.scheduleTask(task1, d);
d.setTime(d.getTime() + ONE_DAY);
scheduler.scheduleTask(task2, d);




因為 Date 是可變的,所以 scheduleTask 方法必須小心地用防范措施將日期參數復制(可能通過 clone())到它的內部數據結構中。不然,task1 和 task2 可能都在明天執行,這可不是所期望的。更糟的是,任務調度程序所用的內部數據結構會變成訛誤。在編寫象 scheduleTask() 這樣的方法時,極其輕易忘記用防范措施復制日期參數。假如忘記這樣做,您就制造了一個難以捕捉的錯誤,這個錯誤不會馬上顯現出來,而且當它暴露時人們要花較長的時間才會捕捉到。不變的 Date 類不可能發生這類錯誤。

固有的線程安全
大多數的線程安全問題發生在當多個線程正在試圖并發地修改一個對象的狀態(寫-寫沖突)時,或當一個線程正試圖訪問一個對象的狀態,而另一個線程正在修改它(讀-寫沖突)時。要防止這樣的沖突,必須同步對共享對象的訪問,以便在對象處于不一致狀態時其它線程不能訪問它們。正確地做到這一點會很難,需要大量文檔來確保正確地擴展程序,還可能對性能產生不利后果。只要正確構造了不變對象(這意味著不讓對象引用從構造函數中轉義),就使它們免除了同步訪問的要求,因為無法更改它們的狀態,從而就不可能存在寫-寫沖突或讀-寫沖突。

不用同步就能自由地在線程間共享對不變對象的引用,可以極大地簡化編寫并發程序的過程,并減少程序可能存在的潛在并發錯誤的數量。

在惡意運行的代碼面前是安全的
把對象當作參數的方法不應變更那些對象的狀態,除非文檔明確說明可以這樣做,或者實際上這些方法具有該對象的所有權。當我們將一個對象傳遞給普通方法時,通常不希望對象返回時已被更改。但是,使用可變對象時,完全會是這樣的。假如將 java.awt.Point 傳遞給諸如 Component.setLocation() 的方法,根本不會阻止 setLocation 修改我們傳入的 Point 的位置,也不會阻止 setLocation 存儲對該點的引用并稍后在另一個方法中更改它。(當然,Component 不這樣做,因為它不魯莽,但是并不是所有類都那么客氣。)現在,Point 的狀態已在我們不知道的情況下更改了,其結果具有潛在危險 — 當點實際上在另一個位置時,我們仍認為它在原來的位置。然而,假如 Point 是不變的,那么這種惡意的代碼就不能以如此令人混亂而危險的方法修改我們的程序狀態了。

良好的鍵
不變對象產生最好的 HashMap 或 HashSet 鍵。有些可變對象根據其狀態會更改它們的 hashCode() 值(如清單 2 中的 StringHolder 示例類)。假如使用這種可變對象作為 HashSet 鍵,然后對象更改了其狀態,那么就會對 HashSet 實現引起混亂 — 假如枚舉集合,該對象仍將出現,但假如用 contains() 查詢集合,它就可能不出現。無需多說,這會引起某些混亂的行為。說明這一情況的清單 2 中的代碼將打印“false”、“1”和“moo”。

清單 2. 可變 StringHolder 類,不適合用作鍵 public class StringHolder {
PRivate String string;
public StringHolder(String s) {

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 留坝县| 舟曲县| 防城港市| 论坛| 云阳县| 丁青县| 大关县| 富阳市| 吉林市| 浙江省| 道真| 丰原市| 常山县| 沙湾县| 乳源| 邹平县| 安新县| 武隆县| 渭源县| 恩施市| 含山县| 凯里市| 阿图什市| 阿鲁科尔沁旗| 会东县| 博乐市| 巴林左旗| 宜章县| 泸溪县| 建德市| 昆山市| 抚宁县| 常德市| 石林| 旺苍县| 辽阳县| 安新县| 彰化市| 万山特区| 文昌市| 宜阳县|