日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

如何理解java中String的不可变性

發(fā)布時(shí)間:2025/3/19 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何理解java中String的不可变性 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

        • 問題
        • String類的聲明
        • final關(guān)鍵字的作用
        • String的不變性
        • String的不變性有哪些好處
        • String真的是絕對(duì)不可變嗎

問題

為什么大家都在說String是不可變的?

String類的聲明

public final class Stringimplements java.io.Serializable, Comparable<String>, CharSequence {/** The value is used for character storage. */private final char value[];......public String(char value[]) {this.value = Arrays.copyOf(value, value.length);}

java中String聲明是final類型,說明String不可繼承,String里面核心存儲(chǔ)值的value是一個(gè)char[]數(shù)組也使用了final修飾,說明value的引用地址是不改變。

final關(guān)鍵字的作用

使用final修飾的變量,編譯器不允許我們做修改的,舉例說明:

@Testpublic void finalTest(){final char[] value = {'a','a','a'};char[] value2 = {'b','b','b'};value = value2;//cannot assign a value to final variable}

上面value = value2這一行會(huì)報(bào)錯(cuò),無(wú)法為final修飾的變量賦值,意思就是使用final修飾的變量的引用不能被更改。但是引用不能被更改不代表不能改變里面的值。如下說所示:

@Testpublic void finalTest() {final char[] value = {'a', 'a', 'a'};System.out.println(value);value[2] = 'b';//將索引位置為2的修改為bSystem.out.println(value);}

打印結(jié)果:

aaa aab

String的不變性

這里簡(jiǎn)單的例子測(cè)試一下String的不可變性

@Testpublic void testString() {String test1 = new String("aaa");StringBuilder test2 = new StringBuilder("aaa");System.out.println("輸出原始的test1:" + test1);System.out.println("輸出原始的test2:" + test2.toString());//追加字符串之后String afaddStr = addString(test1);StringBuilder afaddStrBuild = addStringBuilder(test2);System.out.println("輸出原始的test1:" + test1);System.out.println("輸出原始的test2:" + test2.toString());}/*** 向字符串中添加bbb** @param str*/public String addString(String str) {str = str + "bbb";return str;}/*** 向字符串中追加bbb** @param str*/public StringBuilder addStringBuilder(StringBuilder str) {str.append("bbb");return str;}

結(jié)果輸出:

輸出原始的test1:aaa 輸出原始的test2:aaa 輸出原始的test1:aaa 輸出原始的test2:aaabbb

test1在一頓操作之后還保留了原來(lái)的樣子,但是test2已經(jīng)被改變了,其實(shí)String這種不可變性我們經(jīng)常無(wú)意間使用,最常見的使用場(chǎng)景就是HashSet的值。看如下示例:

@Testpublic void testString2() {String key1 = new String("aaa");StringBuilder key2 = new StringBuilder("aaa");HashSet set = new HashSet<>();set.add(key1);set.add(key2);System.out.println("原始存儲(chǔ)的set值:"+ set.toString());/**************模擬業(yè)務(wù)操作******************/String afaddStr = addString(key1);StringBuilder afaddStrBuild = addStringBuilder(key2);/**************模擬業(yè)務(wù)操作****end***********/System.out.println("業(yè)務(wù)執(zhí)行后set值:"+ set.toString());}/*** 向字符串中添加bbb** @param str*/public String addString(String str) {str = str + "bbb";return str;}/*** 向字符串中追加bbb** @param str*/public StringBuilder addStringBuilder(StringBuilder str) {str.append("bbb");return str;}

如果使用StringBuilder存儲(chǔ)則我們無(wú)意間的業(yè)務(wù)操作會(huì)改變Set中的值,這可能引起不必要的麻煩。

String的不變性有哪些好處

  • 只有當(dāng)字符串是不可變的,字符串池才有可能實(shí)現(xiàn)。字符串池的實(shí)現(xiàn)可以在運(yùn)行時(shí)節(jié)約很多heap空間,因?yàn)椴煌淖址兞慷贾赶虺刂械耐粋€(gè)字符串。如果字符串是可變的,那么String interning將不能實(shí)現(xiàn)(String interning是指對(duì)不同的字符串僅僅只保存一個(gè),即不會(huì)保存多個(gè)相同的字符串),因?yàn)檫@樣的話,如果變量改變了它的值,那么其它指向這個(gè)值的變量的值也會(huì)一起改變。
  • 如果字符串是可變的,那么會(huì)引起很嚴(yán)重的安全問題。譬如,數(shù)據(jù)庫(kù)的用戶名、密碼都是以字符串的形式傳入來(lái)獲得數(shù)據(jù)庫(kù)的連接,或者在socket編程中,主機(jī)名和端口都是以字符串的形式傳入。 因?yàn)樽址遣豢勺兊?#xff0c;所以它的值是不可改變的,否則黑客們可以鉆到空子,改變字符串指向的對(duì)象的值,造成安全漏洞。
  • 因?yàn)樽址遣豢勺兊?#xff0c;所以是多線程安全的,同一個(gè)字符串實(shí)例可以被多個(gè)線程共享。這樣便不用因?yàn)榫€程安全問題而使用同步。字符串自己便是線程安全的。
  • 因?yàn)樽址遣豢勺兊?#xff0c;所以在它創(chuàng)建的時(shí)候hashcode就被緩存了,不需要重新計(jì)算。這就使得字符串很適合作為Map中的鍵,字符串的處理速度要快過其它的鍵對(duì)象。這就是HashMap中的鍵往往都使用字符串。
  • String真的是絕對(duì)不可變嗎

    看如下例子:

    @Testpublic void testString3() throws IllegalAccessException, NoSuchFieldException {String strObj = new String("aaa");System.out.println("反射執(zhí)行前字符串:" + strObj);System.out.println("反射執(zhí)行前的hash值:" + strObj.hashCode());Field field = strObj.getClass().getDeclaredField("value");field.setAccessible(true);char[] value = (char[]) field.get(strObj);value[2] = 'b';System.out.println("反射執(zhí)行后字符串:" + strObj);System.out.println("反射執(zhí)行后的hash值:" + strObj.hashCode());}

    打印結(jié)果如下:

    反射執(zhí)行前字符串:aaa 反射執(zhí)行前的hash值:96321 反射執(zhí)行后字符串:aab 反射執(zhí)行后的hash值:96321

    說明通過反射我們是可以修改String的值的

    參考如下:

    https://www.zhihu.com/question/20618891

    總結(jié)

    以上是生活随笔為你收集整理的如何理解java中String的不可变性的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。