成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專欄INFORMATION COLUMN

String:String類型為什么不可變

zhiwei / 1020人閱讀

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

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

String 真的不可變嗎?

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

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

String 真的不可變?

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

反射的方式操作 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屬性的訪問(wèn)權(quán)限  
        valueFieldOfString.setAccessible(true);  
          
        //獲取s對(duì)象上的value屬性的值  
        char[] value = (char[]) valueFieldOfString.get(s);  
          
        //改變value所引用的數(shù)組中的第5個(gè)字符  
        value[5] = "_";  
          
        System.out.println("s = " + s);    //Hello_World  

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

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

安全

引發(fā)安全問(wèn)題,譬如,數(shù)據(jù)庫(kù)的用戶名、密碼都是以字符串的形式傳入來(lái)獲得數(shù)據(jù)庫(kù)的連接,或者在socket編程中,主機(jī)名和端口都是以字符串的形式傳入。因?yàn)樽址遣豢勺兊?,所以它的值是不可改變的,否則黑客們可以鉆到空子,改變字符串指向的對(duì)象的值,造成安全漏洞

保證線程安全,在并發(fā)場(chǎng)景下,多個(gè)線程同時(shí)讀寫(xiě)資源時(shí),會(huì)引競(jìng)態(tài)條件,由于 String 是不可變的,不會(huì)引發(fā)線程的問(wèn)題而保證了線程

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

性能

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

實(shí)例代碼:

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ù)實(shí)現(xiàn)

打開(kāi)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 修飾,說(shuō)明該類不可繼承

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

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

final int[] value={1,2,3}
      int[] another={4,5,6};
value=another;    // 編譯器報(bào)錯(cuò),final不可變

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

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

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

為了實(shí)現(xiàn) String 不可變,關(guān)鍵在于Java的開(kāi)發(fā)者在設(shè)計(jì)和開(kāi)發(fā) String 的過(guò)程中,沒(méi)有暴露任何的內(nèi)部成員,與此同時(shí) API 的設(shè)計(jì)是均沒(méi)有操作 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() 的方式返回新的字符串
    }
    

整個(gè)String設(shè)成final禁止繼承,避免被其他人繼承后破壞。所以String是不可變的關(guān)鍵都在底層的實(shí)現(xiàn),而不是一個(gè)final。考驗(yàn)的是工程師構(gòu)造數(shù)據(jù)類型,封裝數(shù)據(jù)的功力。

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

String 不可變性的圖示:

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/70172.html

相關(guān)文章

  • Java的String可變

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

    atinosun 評(píng)論0 收藏0
  • java中的String什么可變

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

    cfanr 評(píng)論0 收藏0
  • Java程序員常犯的10個(gè)錯(cuò)誤

    摘要:原文出自本文總結(jié)了程序員常犯的個(gè)錯(cuò)誤??梢钥纯礊槭裁丛谥斜辉O(shè)計(jì)成不可變父類和子類的構(gòu)造函數(shù)以上這段代碼出現(xiàn)編譯錯(cuò)誤,因?yàn)槟J(rèn)的父類構(gòu)造函數(shù)未定義。如果程序員定義構(gòu)造函數(shù),編譯器將不插入默認(rèn)的無(wú)參數(shù)構(gòu)造函數(shù)。 原文出自:http://www.programcreek.com/2014/05/top-10-mistakes-java-developers-make/ 本文總結(jié)了J...

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

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

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

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

    Andrman 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<