亚洲中字慕日产2020,大陆极品少妇内射AAAAAA,无码av大香线蕉伊人久久,久久精品国产亚洲av麻豆网站

資訊專欄INFORMATION COLUMN

String:String類型為什么不可變

zhiwei / 1056人閱讀

摘要:性能當(dāng)字符串是不可變時,字符串常量池才有意義。字符串常量池的出現(xiàn),可以減少創(chuàng)建相同字面量的字符串,讓不同的引用指向池中同一個字符串,為運行時節(jié)約很多的堆內(nèi)存。

在學(xué)習(xí)Java的過程中,我們會被告知 String 被設(shè)計成不可變的類型。為什么 String 會被 Java 開發(fā)者有如此特殊的對待?他們的設(shè)計意圖和設(shè)計理念到底是什么?因此,我?guī)е韵氯齻€問題,對
String 進(jìn)行剖析:

String 真的不可變嗎?

為什么會將 String 設(shè)計為不可變?

如何通過技術(shù)實現(xiàn)實現(xiàn) String 不可變 ?

String 真的不可變?

String 底層實現(xiàn):

public final class String
    implements java.io.Serializable, Comparable, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0
    
    //other codes
}

String 的底層實現(xiàn)是依靠 char[] 數(shù)組,既然依靠的是基礎(chǔ)類型變量,那么他一定是可變的, String 之所以不可變,是因為 Java 的開發(fā)者通過技術(shù)實現(xiàn),隔絕了使用者對 String 的底層數(shù)據(jù)的操作。但是,我們可以同反射的機制,操作 String 的底層,檢驗其不可變的猜想。

反射的方式操作 String :

        //創(chuàng)建字符串"Hello World", 并賦給引用s  
        String s = "Hello World";   
          
        System.out.println("s = " + s);    // Hello World  
          
        //獲取String類中的value字段  
        Field valueFieldOfString = String.class.getDeclaredField("value");  
          
        //改變value屬性的訪問權(quán)限  
        valueFieldOfString.setAccessible(true);  
          
        //獲取s對象上的value屬性的值  
        char[] value = (char[]) valueFieldOfString.get(s);  
          
        //改變value所引用的數(shù)組中的第5個字符  
        value[5] = "_";  
          
        System.out.println("s = " + s);    //Hello_World  

通過兩次字符串的輸出,我們可以看到,String 被改變了,但是在代碼里,幾乎不會使用反射的機制去操作 String 字符串,所以,我們會認(rèn)為 String 類型是不可變的。

為什么會將 String 設(shè)計為不可變

安全

引發(fā)安全問題,譬如,數(shù)據(jù)庫的用戶名、密碼都是以字符串的形式傳入來獲得數(shù)據(jù)庫的連接,或者在socket編程中,主機名和端口都是以字符串的形式傳入。因為字符串是不可變的,所以它的值是不可改變的,否則黑客們可以鉆到空子,改變字符串指向的對象的值,造成安全漏洞

保證線程安全,在并發(fā)場景下,多個線程同時讀寫資源時,會引競態(tài)條件,由于 String 是不可變的,不會引發(fā)線程的問題而保證了線程

HashCode,當(dāng) String 被創(chuàng)建出來的時候,hashcode也會隨之被緩存,hashcode的計算與value有關(guān),若 String 可變,那么 hashcode 也會隨之變化,針對于 Map、Set 等容器,他們的鍵值需要保證唯一性和一致性,因此,String 的不可變性使其比其他對象更適合當(dāng)容器的鍵值。

性能

當(dāng)字符串是不可變時,字符串常量池才有意義。字符串常量池的出現(xiàn),可以減少創(chuàng)建相同字面量的字符串,讓不同的引用指向池中同一個字符串,為運行時節(jié)約很多的堆內(nèi)存。若字符串可變,字符串常量池失去意義,基于常量池的String.intern()方法也失效,每次創(chuàng)建新的 String 將在堆內(nèi)開辟出新的空間,占據(jù)更多的內(nèi)存

實例代碼:

String 的不可變性:

    public static String appendStr(String s){
        s+="bbb";
        return s;
    }

    //可變的StringBuilder
    public static StringBuilder appendSb(StringBuilder sb){
        return sb.append("bbb");
    }

    public static void main(String[] args){
        //String做參數(shù)
        String s=new String("aaa");
        String ns=Test.appendStr(s);
        System.out.println("String aaa >>> "+s.toString()); // aaa

        //StringBuilder做參數(shù)
        StringBuilder sb=new StringBuilder("aaa");
        StringBuilder nsb=Test.appendSb(sb);
        System.out.println("StringBuilder aaa >>> "+sb.toString()); // aaabbb
    }
String 不可變的技術(shù)實現(xiàn)

打開JDK的源碼:

public final class String
    implements java.io.Serializable, Comparable, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0
    
    //other codes
}

String 類由關(guān)鍵字 final 修飾,說明該類不可繼承

char value[] 屬性也被 final 所修飾,說明 value 的引用在創(chuàng)建之后,就不能被改變

以上兩點并不能完全實現(xiàn) String 不可變 ,原因在于:

final int[] value={1,2,3}
      int[] another={4,5,6};
value=another;    // 編譯器報錯,final不可變

value 被 final 修飾,只能保證引用不被改變,但是 value 所指向的堆中的數(shù)組,才是真實的數(shù)據(jù),只要能夠操作堆中的數(shù)組,依舊能改變數(shù)據(jù)?!窘忉專篠tring實際上是可變的】

final int[] value={1,2,3};
value[2]=100;  //這時候數(shù)組里已經(jīng)是{1,2,100}

所有的成員屬性均被 private 關(guān)鍵字所修飾

為了實現(xiàn) String 不可變,關(guān)鍵在于Java的開發(fā)者在設(shè)計和開發(fā) String 的過程中,沒有暴露任何的內(nèi)部成員,與此同時 API 的設(shè)計是均沒有操作 value 的值 , 而是采用 new String() 的方式返回新的字符串,保證了 String 的不可變。

JDK String API 源碼:

    public static String valueOf(char c) {
        char data[] = {c};
        return new String(data, true);  //采用 new String() 的方式返回新的字符串
    }
    
    

    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);  //采用 new String() 的方式返回新的字符串
    }
    

整個String設(shè)成final禁止繼承,避免被其他人繼承后破壞。所以String是不可變的關(guān)鍵都在底層的實現(xiàn),而不是一個final??简灥氖枪こ處煒?gòu)造數(shù)據(jù)類型,封裝數(shù)據(jù)的功力。

String s = "abcd";
s = "abcdel";

String 不可變性的圖示:

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://www.ezyhdfw.cn/yun/70172.html

相關(guān)文章

  • Java的String可變

    摘要:但是通過構(gòu)造函數(shù)的并不是。通過構(gòu)造函數(shù)創(chuàng)建的變量在機制上與其他對象一致,都是在上創(chuàng)建新的對象,然后把引用賦給變量。此外,的方法和等方法實現(xiàn)均是調(diào)用了構(gòu)造函數(shù)創(chuàng)建了新的對象,所以他們返回的也都是存在于上的新對象。 String經(jīng)常在一個語言中或多或少都有些特殊地位。在Java亦不例外。今天先來討論,String是不可變的。 String是引用類型,String變量儲存一個地址,地址指向內(nèi)...

    atinosun 評論0 收藏0
  • java中的String什么可變

    摘要:什么是不可變對象如果一個對象,在它創(chuàng)建完成后,不能在改變它的狀態(tài),那么這個對象就是不可變的。而在中,是封裝的數(shù)組,是在這個數(shù)組中的起始位置,是所占的字符的個數(shù)。 這是之前在網(wǎng)上看到的一個問題,我就是總結(jié)一下。什么是不可變對象:如果一個對象,在它創(chuàng)建完成后,不能在改變它的狀態(tài),那么這個對象就是不可變的。不能改變這個對象的狀態(tài)就是:不改變對象內(nèi)的成員變量,包括基本數(shù)據(jù)類型的值不能改變,引用...

    cfanr 評論0 收藏0
  • Java程序員常犯的10個錯誤

    摘要:原文出自本文總結(jié)了程序員常犯的個錯誤。可以看看為什么在中被設(shè)計成不可變父類和子類的構(gòu)造函數(shù)以上這段代碼出現(xiàn)編譯錯誤,因為默認(rèn)的父類構(gòu)造函數(shù)未定義。如果程序員定義構(gòu)造函數(shù),編譯器將不插入默認(rèn)的無參數(shù)構(gòu)造函數(shù)。 原文出自:http://www.programcreek.com/2014/05/top-10-mistakes-java-developers-make/ 本文總結(jié)了J...

    Andrman 評論0 收藏0
  • 第3章:抽象數(shù)據(jù)類型(ADT)和面向?qū)ο缶幊蹋∣OP) 3.1數(shù)據(jù)類型類型檢查

    摘要:所有變量的類型在編譯時已知在程序運行之前,因此編譯器也可以推導(dǎo)出所有表達(dá)式的類型。像變量的類型一樣,這些聲明是重要的文檔,對代碼讀者很有用,并由編譯器進(jìn)行靜態(tài)檢查。對象類型的值對象類型的值是由其類型標(biāo)記的圓。 大綱 1.編程語言中的數(shù)據(jù)類型2.靜態(tài)與動態(tài)數(shù)據(jù)類型3.類型檢查4.易變性和不變性5.快照圖6.復(fù)雜的數(shù)據(jù)類型:數(shù)組和集合7.有用的不可變類型8.空引用9.總結(jié) 編程語言中的數(shù)據(jù)...

    zhangqh 評論0 收藏0
  • 經(jīng)驗拾憶(純手工)=> Python基本數(shù)據(jù)類型

    摘要:不要疑惑,告訴你答案這個代表正負(fù)號的正。雖然一點技術(shù)含量沒有,但是你要懂序列也許叫可迭代對象更為合適,但是我喜歡叫序列。 數(shù)據(jù)結(jié)構(gòu) 可變類型與不可變類型(重頭戲) 基操: 可變類型:[], {} # 可增刪改 查 不可變類型: int float str () # 無法增刪改, 只可查 升操: + 與...

    Andrman 評論0 收藏0

發(fā)表評論

0條評論

zhiwei

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<