色哟哟视频在线观看-色哟哟视频在线-色哟哟欧美15最新在线-色哟哟免费在线观看-国产l精品国产亚洲区在线观看-国产l精品国产亚洲区久久

您好,歡迎來電子發燒友網! ,新用戶?[免費注冊]

您的位置:電子發燒友網>源碼下載>java源碼下載>

java中string不可變的原因

大小:0.4 MB 人氣:0 2017-09-27 需要積分:1

  區分對象和對象的引用

  對于Java初學者, 對于String是不可變對象總是存有疑惑。看下面代碼:

  String s = “ABCabc”;System .out.println( “s = ”+ s) ;s = “123456”;System .out.println( “s = ”+ s) ;

  打印結果為:

  s = ABCabc s = 123456

  首先創建一個String對象s,然后讓s的值為“ABCabc”, 然后又讓s的值為“123456”。 從打印結果可以看出,s的值確實改變了。那么怎么還說String對象是不可變的呢? 其實這里存在一個誤區: s只是一個String對象的引用,并不是對象本身。對象在內存中是一塊內存區,成員變量越多,這塊內存區占的空間越大。引用只是一個4字節的數據,里面存放了它所指向的對象的地址,通過這個地址可以訪問對象。

  也就是說,s只是一個引用,它指向了一個具體的對象,當s=“123456”; 這句代碼執行過之后,又創建了一個新的對象“123456”, 而引用s重新指向了這個心的對象,原來的對象“ABCabc”還在內存中存在,并沒有改變。內存結構如下圖所示:

  java中string不可變的原因

  Java和C++的一個不同點是, 在Java中不可能直接操作對象本身,所有的對象都由一個引用指向,必須通過這個引用才能訪問對象本身,包括獲取成員變量的值,改變對象的成員變量,調用對象的方法等。而在C++中存在引用,對象和指針三個東西,這三個東西都可以訪問對象。其實,Java中的引用和C++中的指針在概念上是相似的,他們都是存放的對象在內存中的地址值,只是在Java中,引用喪失了部分靈活性,比如Java中的引用不能像C++中的指針那樣進行加減運算。

  為什么String對象是不可變的?

  要理解String的不可變性,首先看一下String類中都有哪些成員變量。 在JDK1.6中,String的成員變量有以下幾個:

  public finalclassStringimplements java.io.Serializable, Comparable《String》, CharSequence { /** The value is used for character storage. */privatefinalchar value[]; /** The offset is the first index of the storage that is used. */privatefinalint offset; /** The count is the number of characters in the String. */privatefinalint count; /** Cache the hash code for the string */privateint hash; // Default to 0

  在JDK1.7中,String類做了一些改動,主要是改變了substring方法執行時的行為,這和本文的主題不相關。JDK1.7中String類的主要成員變量就剩下了兩個:

  public finalclassStringimplements java.io.Serializable, Comparable《String》, CharSequence { /** The value is used for character storage. */privatefinalchar value[]; /** Cache the hash code for the string */privateint hash; // Default to 0

  由以上的代碼可以看出, 在Java中String類其實就是對字符數組的封裝。JDK6中, value是String封裝的數組,offset是String在這個value數組中的起始位置,count是String所占的字符的個數。在JDK7中,只有一個value變量,也就是value中的所有字符都是屬于String這個對象的。這個改變不影響本文的討論。 除此之外還有一個hash成員變量,是該String對象的哈希值的緩存,這個成員變量也和本文的討論無關。在Java中,數組也是對象。 所以value也只是一個引用,它指向一個真正的數組對象。其實執行了String s = “ABCabc”; 這句代碼之后,真正的內存布局應該是這樣的:

  java中string不可變的原因

  value,offset和count這三個變量都是private的,并且沒有提供setValue, setOffset和setCount等公共方法來修改這些值,所以在String類的外部無法修改String。也就是說一旦初始化就不能修改, 并且在String類的外部不能訪問這三個成員。此外,value,offset和count這三個變量都是final的, 也就是說在String類內部,一旦這三個值初始化了, 也不能被改變。所以可以認為String對象是不可變的了。

  那么在String中,明明存在一些方法,調用他們可以得到改變后的值。這些方法包括substring, replace, replaceAll, toLowerCase等。例如如下代碼:

  String a= “ABCabc”; System.out.println( “a = ”+ a) ; a= a.replace(‘ A’, ‘ a’) ;System.out.println( “a = ”+ a) ;

  打印結果為:

  a = ABCabca = aBCabc

  那么a的值看似改變了,其實也是同樣的誤區。再次說明, a只是一個引用, 不是真正的字符串對象,在調用a.replace(‘A’, ‘a’)時, 方法內部創建了一個新的String對象,并把這個心的對象重新賦給了引用a。String中replace方法的源碼可以說明問題:

  java中string不可變的原因

  讀者可以自己查看其他方法,都是在方法內部重新創建新的String對象,并且返回這個新的對象,原來的對象是不會被改變的。這也是為什么像replace, substring,toLowerCase等方法都存在返回值的原因。也是為什么像下面這樣調用不會改變對象的值:

  String ss = “123456”;System .out.println( “ss = ”+ ss) ;ss .replace( ‘1’, ‘0’) ;System.out.println( “ss = ”+ ss) ;

  打印結果:

  ss = 123456 ss = 123456String對象真的不可變嗎?

  從上文可知String的成員變量是private final 的,也就是初始化之后不可改變。那么在這幾個成員中, value比較特殊,因為他是一個引用變量,而不是真正的對象。value是final修飾的,也就是說final不能再指向其他數組對象,那么我能改變value指向的數組嗎? 比如將數組中的某個位置上的字符變為下劃線“_”。 至少在我們自己寫的普通代碼中不能夠做到,因為我們根本不能夠訪問到這個value引用,更不能通過這個引用去修改數組。

  那么用什么方式可以訪問私有成員呢? 沒錯,用反射, 可以反射出String對象中的value屬性, 進而改變通過獲得的value引用改變數組的結構。下面是實例代碼:

  /** * Java學習交流QQ群:589809992 我們一起學Java! */publicstaticvoidtestReflection()throwsException { //創建字符串“Hello World”, 并賦給引用sString s = “Hello World”; System.out.println( “s = ”+ s); //Hello World//獲取String類中的value字段Field valueFieldOfString = String.class.getDeclaredField( “value”); //改變value屬性的訪問權限valueFieldOfString.setAccessible( true); //獲取s對象上的value屬性的值char[] value = (char[]) valueFieldOfString.get(s); //改變value所引用的數組中的第5個字符value[ 5] = ‘_’; System.out.println( “s = ”+ s); //Hello_World}

  打印結果為:

  s = Hello World s = Hello_World

  在這個過程中,s始終引用的同一個String對象,但是再反射前后,這個String對象發生了變化, 也就是說,通過反射是可以修改所謂的“不可變”對象的。但是一般我們不這么做。這個反射的實例還可以說明一個問題:如果一個對象,他組合的其他對象的狀態是可以改變的,那么這個對象很可能不是不可變對象。例如一個Car對象,它組合了一個Wheel對象,雖然這個Wheel對象聲明成了private final 的,但是這個Wheel對象內部的狀態可以改變, 那么就不能很好的保證Car對象不可變。

非常好我支持^.^

(0) 0%

不好我反對

(0) 0%

用戶評論

      ?
      主站蜘蛛池模板: 单亲妈妈3韩国电影免费观看 | 解开白丝老师的短裙猛烈进入 | 成人做视频免费 | 婷婷综合亚洲爱久久 | 日日夜夜影院在线播放 | 午夜片神马影院福利 | 性白俄罗斯高清xxxxx | 色姣姣狠狠撩综合网 | 啪啪漫画无遮挡全彩h同人 啪啪激情婷婷久久婷婷色五月 | 午夜无码国产理论在线 | 国产精品69人妻无码久久久 | 青青青青草原国产免费 | 国产欧美亚洲综合第一页 | 神马午夜不卡片 | 亚洲视频中文字幕在线观看 | 色综合五月激情综合色一区 | a视频免费在线观看 | 国产高潮国产高潮久久久久久 | 精品国产国产精2020久久日 | 暖暖日本手机免费完整版在线观看 | 一本色道久久88综合日韩精品 | 沈阳熟女露脸对白视频 | 国产精品人妻无码99999 | 亚洲九九精品 | 国产 日韩 欧美 高清 亚洲 | 高H各种PLAY全肉NP | 欧美高跟镣铐bdsm视频 | 久久综合给合久久狠狠狠… | 夜夜澡人人爽人人喊_欧美 夜夜骑夜夜欢 | 在线不卡日本v二区 | 国产精品乱码色情一区二区视频 | 奇米精品一区二区三区在线观看 | 我要干av | 青娱乐视觉盛宴国产视频 | 亚洲久久少妇中文字幕 | 久久久久久久久亚洲 | 耻辱诊察室1一4集动漫在线观看 | 把腿张开JI巴CAO死你H教室 | 国产手机精品一区二区 | 国产手机在线精品 | 色哟哟网站入口在线观看视频 |