Java不可變類

0. 幾個問題

  1. 什么是不可變類蝎亚?
  2. 不可變類的優(yōu)缺點是什么?
  3. 常見的不可變類有哪些先馆?String為什么要設(shè)計成不可變類发框?
  4. 如何自己設(shè)計一個不可變類?
    帶著這幾個問題閱讀本文以期能對Java的不可變類有一個全面的了解煤墙。

1. 什么是不可變類

不可變類是指類的實例一旦創(chuàng)建后梅惯,不能改變其成員變量的值宪拥。
與之對應(yīng)的,可變類的實例創(chuàng)建后可以改變其成員變量的值铣减。

2. 不可變類的優(yōu)缺點

  • 優(yōu)點:
    1. 效率她君,例如字符串常量池,字符串常量池可以將一些字符常量放在常量池中重復(fù)使用葫哗,避免每次都重新創(chuàng)建相同的對象缔刹、節(jié)省存儲空間。但如果字符串是可變的劣针,此時相同內(nèi)容的String還指向常量池的同一個內(nèi)存空間校镐,當(dāng)某個變量改變了該內(nèi)存的值時,其他遍歷的值也會發(fā)生改變捺典。所以不符合常量池設(shè)計的初衷鸟廓。
    2. 安全性,不可變對象天生是線程安全的襟己,在不同線程共享對象肝箱,不需要同步機(jī)制,因為對象的值是固定的稀蟋。
  • 缺點:
    1. 資源開銷煌张,對象需要頻繁的修改屬性,則每一次修改都會新創(chuàng)建一個對象退客,產(chǎn)生大量的資源開銷骏融。

3. 常見的不可變類有哪些?String為什么要設(shè)計成不可變類萌狂?

常見的不可變類:String Integer Long等類型
String設(shè)計成不可變類主要是出于效率和安全性考慮档玻。

4. 如何自己設(shè)計一個不可變類?

  1. 類使用final修飾符修飾茫藏,保證類不能被繼承误趴。
    如果類可以被繼承會破壞類的不可變性機(jī)制,只要繼承類覆蓋父類的方法并且繼承類可以改變成員變量值务傲,那么一旦子類以父類的形式出現(xiàn)時凉当,不能保證當(dāng)前類是否可變。
  2. 類的成員變量都應(yīng)該是private final的售葡,保證成員變量不可改變看杭。
  3. 任何獲取/修改屬性的方法都不應(yīng)作用于屬性本身。
    • 不提供修改成員變量的方法挟伙,例如setter方法楼雹。
    • getter方法不能返回對象本身,要返回對象的拷貝,防止對象外泄贮缅。
    • 修改對象的屬性時要返回新對象
  4. 對成員變量的初始化通過構(gòu)造器進(jìn)行榨咐,并進(jìn)行深拷貝。
    如果使用傳入的參數(shù)直接賦值谴供,則傳遞的只是引用块茁,仍然可以通過外部變量改變它的值。

5. String類的不可變性分析

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
    ...
    /**
     * Allocates a new {@code String} so that it represents the sequence of
     * characters currently contained in the character array argument. The
     * contents of the character array are copied; subsequent modification of
     * the character array does not affect the newly created string.
     *
     * @param  value
     *         The initial value of the string
     */
    public String(char value[]) {
        this.value = Arrays.copyOf(value, value.length);
    }
    ...
    /**
     * Converts this string to a new character array.
     *
     * @return  a newly allocated character array whose length is the length
     *          of this string and whose contents are initialized to contain
     *          the character sequence represented by this string.
     */
    public char[] toCharArray() {
        // Cannot use Arrays.copyOf because of class initialization order issues
        char result[] = new char[value.length];
        System.arraycopy(value, 0, result, 0, value.length);
        return result;
    }
}

可以看出String類的設(shè)計遵循以下原則:

  1. String類被final修飾憔鬼,不可繼承
  2. string內(nèi)部所有成員都設(shè)置為私有變量
  3. 不存在value的setter
  4. 并將value和offset設(shè)置為final龟劲。
  5. 當(dāng)傳入可變數(shù)組value[]時胃夏,進(jìn)行copy而不是直接將value[]復(fù)制給內(nèi)部變量.
  6. 獲取value時不是直接返回對象引用轴或,而是返回對象的copy.

這都符合上面總結(jié)的不變類型的特性,也保證了String類型是不可變的類仰禀。

但是照雁,即使是不可變類,通過反射仍然可以改變其屬性的值

String s = "hello world";
System.out.println("s=" + s);
try {
    Field v = String.class.getDeclaredField("value");
    v.setAccessible(true);
    char[] c = (char[]) v.get(s);
    c[5] = '_';
    System.out.println("s=" + s);
} catch (NoSuchFieldException nfe) {
    nfe.printStackTrace();
} catch (IllegalAccessException iae) {
    iae.printStackTrace();
}

輸出結(jié)果為:

s=hello world
s=hello_world

6. 參考

  1. String源碼
  2. JAVA不可變類(immutable)機(jī)制與String的不可變性
  3. 為什么Java的string類要設(shè)成immutable(不可變的)
  4. JAVA的可變類與不可變類
  5. Java不可變類機(jī)制淺析
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末答恶,一起剝皮案震驚了整個濱河市饺蚊,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌悬嗓,老刑警劉巖污呼,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異包竹,居然都是意外死亡燕酷,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門周瞎,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苗缩,“玉大人,你說我怎么就攤上這事声诸〗囱龋” “怎么了?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵彼乌,是天一觀的道長泻肯。 經(jīng)常有香客問我,道長慰照,這世上最難降的妖魔是什么软免? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮焚挠,結(jié)果婚禮上膏萧,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好榛泛,可當(dāng)我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布蝌蹂。 她就那樣靜靜地躺著,像睡著了一般曹锨。 火紅的嫁衣襯著肌膚如雪孤个。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天沛简,我揣著相機(jī)與錄音齐鲤,去河邊找鬼。 笑死椒楣,一個胖子當(dāng)著我的面吹牛给郊,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播捧灰,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼淆九,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了毛俏?” 一聲冷哼從身側(cè)響起炭庙,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎煌寇,沒想到半個月后焕蹄,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡阀溶,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年腻脏,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片淌哟。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡迹卢,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出徒仓,到底是詐尸還是另有隱情腐碱,我是刑警寧澤,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布掉弛,位于F島的核電站症见,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏殃饿。R本人自食惡果不足惜谋作,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望乎芳。 院中可真熱鬧遵蚜,春花似錦帖池、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至寂殉,卻和暖如春囚巴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背友扰。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工彤叉, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人村怪。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓秽浇,卻偏偏與公主長得像,于是被迫代替她去往敵國和親实愚。 傳聞我的和親對象是個殘疾皇子兼呵,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法兔辅,類相關(guān)的語法腊敲,內(nèi)部類的語法,繼承相關(guān)的語法维苔,異常的語法碰辅,線程的語...
    子非魚_t_閱讀 31,625評論 18 399
  • 一、Java 簡介 Java是由Sun Microsystems公司于1995年5月推出的Java面向?qū)ο蟪绦蛟O(shè)計...
    子非魚_t_閱讀 4,186評論 1 44
  • 注:都是在百度搜索整理的答案介时,如有侵權(quán)和錯誤没宾,希告知更改。 一沸柔、哪些情況下的對象會被垃圾回收機(jī)制處理掉 ?當(dāng)對象對...
    Jenchar閱讀 3,224評論 3 2
  • 一個人的精神發(fā)育史,應(yīng)該是一個人的閱讀史工三。一個民族的精神境界迁酸,在很大程度上取決于全民族的閱讀水平。 面對這個提問俭正,...
    瑩光灼華閱讀 4,227評論 191 219
  • 大雁塔奸鬓。。唐城墻遺址公園掸读。串远。曲江池遺址公園宏多。。永興坊肉夾饃 俺們本來今天想要去陜博的澡罚,但是陜博人實在是太多了绷落,沒招...
    不變的是那對wx閱讀 261評論 0 1