摘要:但是通過構造函數(shù)的并不是。通過構造函數(shù)創(chuàng)建的變量在機制上與其他對象一致,都是在上創(chuàng)建新的對象,然后把引用賦給變量。此外,的方法和等方法實現(xiàn)均是調(diào)用了構造函數(shù)創(chuàng)建了新的對象,所以他們返回的也都是存在于上的新對象。
String經(jīng)常在一個語言中或多或少都有些特殊地位。在Java亦不例外。今天先來討論,String是不可變的。
String是引用類型,String變量儲存一個地址,地址指向內(nèi)存堆中的String對象。當我們說變量不可變,有兩種不可變性:
變量儲存的地址不可變;
地址指向的對象內(nèi)容不可變。
String的不可變指的是哪一種?下面用例子來看。
通常有人在疑問String不可變時,會舉這樣的例子:我們平時不都像下面這樣在“修改”String字符串嗎:
String s = "hello,world"; s = "Hello,coder"; System.out.println(s); //Hello,coder
我認為這只是一個語義上的誤導。賦值操作符=通常作用于基本數(shù)據(jù)類型時,確是修改變量的值。所以在這里讓人誤以為也是修改了變量的內(nèi)容。但是對于引用類型String,s="Hello,coder"的實際作用是將變量s指向另一個內(nèi)容為Hello,coder的新的對象。
所以,對于String不可變性的結論顯而易見了:String變量指向的地址是可變的,他的不可變性當然說的是第二種——地址指向的對象內(nèi)容不可變。
縱覽String的方法,String類確實沒有提供能從String外部修改對象的方法。我們熟悉的replace,substring等等方法都要返回一個String,其實都是在返回一個新的對象,而沒有修改原有的對象。
為什么要設計成對象內(nèi)容不可變?
String常量池一個說法是便于實現(xiàn)String常量池。String存在于常量池中,當新創(chuàng)建一個字符串變量,如果字符串在內(nèi)存中已經(jīng)存在,那么就會把這個已經(jīng)存在于常量池對象的地址賦給變量。這樣可節(jié)省內(nèi)存開銷。
但這不完全對。
只有兩種情況下創(chuàng)建的String變量,他們才會指向常量池中的同一對象:
String是字面直接量賦值創(chuàng)建。字面直接量是編譯期常量,變量會指向常量池中的對象。所有字面量賦值創(chuàng)建的String變量都會指向常量池中的對象。
通過String類的intern()方法得到String變量也是指向常量池中的對象。
但是通過構造函數(shù)new String()的并不是。通過構造函數(shù)創(chuàng)建的String變量在機制上與其他對象一致,都是在heap上創(chuàng)建新的對象,然后把引用賦給變量。
簡單例子驗證。
String a = "hello,world"; String b = "hello,world"; boolean c = (a == b); //true String d = new String("hello,world"); String e = new String("hello,world");; boolean f = (d == e); //false String g = d.intern(); boolean h = (a == g); //true
此外,String的方法substring,relpace和split等方法實現(xiàn)均是調(diào)用了構造函數(shù)創(chuàng)建了新的對象,所以他們返回的String也都是存在于heap上的新對象。
綜上來看似乎節(jié)省不了多少內(nèi)存,畢竟程序中編譯常量是少數(shù),大多數(shù)String都是在運行時產(chǎn)生。
線程安全這一點顯而易見,對象內(nèi)容都不可變了,自然不會有線程安全問題。
代碼安全String經(jīng)常被用來存儲server connection, database connection或者file path等等。如果String可變,一旦代碼某處改動了字符串,會對系統(tǒng)有安全和穩(wěn)定性威脅。發(fā)生在其他普通字符串,則是不可預料的bug。尤其是代碼復雜度很高的時候,一個字符串對象被多個變量引用,直接修改對象內(nèi)容,引起所有引用該對象的變量都發(fā)生變化,容易引起bug。
當然這一點主要是降低程序員的錯誤和bug的可能。
其實,話說回來,在JAVA里,String不可變也并非特殊,所有包裝類Interger,Boolean等都是不可變類。
文章版權歸作者所有,未經(jīng)允許請勿轉載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉載請注明本文地址:http://www.ezyhdfw.cn/yun/77028.html
摘要:文本已收錄至我的倉庫,歡迎記錄一次在寫代碼時愚蠢的操作,本文涉及到的知識點不可變性一交代背景我這邊有一個系統(tǒng),提供一個接口去發(fā)送短信。 前言 只有光頭才能變強。文本已收錄至我的GitHub倉庫,歡迎Star:https://github.com/ZhongFuCheng3y/3y 記錄一次在寫代碼時愚蠢的操作,本文涉及到的知識點:String不可變性 一、交代背景 我這邊有一個系統(tǒng),...
摘要:的不變性,如下圖所示,當你改變了的之后指向了一個新的對象原對象不做改變。但其引用的數(shù)組是可變的。所以的不可變性的關鍵并不是的作用。同時編寫者為了避免因為的不可變性導致占用大量空間,為此設計了字符串常量池 在貓眼的面試中被面試官問到為什么String的字符串是不變的。當時我的回答是因為String類是用final關鍵字修飾的,當被問到為什么用 final修飾就是不可變的時候我發(fā)現(xiàn)自己說的...
摘要:所有變量的類型在編譯時已知在程序運行之前,因此編譯器也可以推導出所有表達式的類型。像變量的類型一樣,這些聲明是重要的文檔,對代碼讀者很有用,并由編譯器進行靜態(tài)檢查。對象類型的值對象類型的值是由其類型標記的圓。 大綱 1.編程語言中的數(shù)據(jù)類型2.靜態(tài)與動態(tài)數(shù)據(jù)類型3.類型檢查4.易變性和不變性5.快照圖6.復雜的數(shù)據(jù)類型:數(shù)組和集合7.有用的不可變類型8.空引用9.總結 編程語言中的數(shù)據(jù)...
摘要:這兩個操作符都是編譯器默認引入了類,最后都調(diào)用方法返回對象,臨時對象被回收,因此效率極為低下 Java String類筆記 聲明 文章均為本人技術筆記,轉載請注明出處https://segmentfault.com/u/yzwall String的不可變性 String的不可變性 // String declaration public final class String ...
摘要:性能當字符串是不可變時,字符串常量池才有意義。字符串常量池的出現(xiàn),可以減少創(chuàng)建相同字面量的字符串,讓不同的引用指向池中同一個字符串,為運行時節(jié)約很多的堆內(nèi)存。 在學習Java的過程中,我們會被告知 String 被設計成不可變的類型。為什么 String 會被 Java 開發(fā)者有如此特殊的對待?他們的設計意圖和設計理念到底是什么?因此,我?guī)е韵氯齻€問題,對 String 進行剖析: ...
閱讀 940·2023-04-26 00:11
閱讀 2734·2021-11-04 16:13
閱讀 2186·2021-09-09 09:33
閱讀 1551·2021-08-20 09:35
閱讀 3933·2021-08-09 13:42
閱讀 3674·2019-08-30 15:55
閱讀 1193·2019-08-30 15:55
閱讀 2281·2019-08-30 13:55