第一茧痕,簡介
????????String是java語言非尘淇基礎(chǔ)和重要的類丹墨,提供了構(gòu)造和管理字符串的各種基本邏輯廊遍。它是典型的immutable類,被聲明成為final class贩挣,所有屬性也都是final的喉前。也由于它的不可變性,類似拼接王财,裁剪字符串等動作卵迂,都會產(chǎn)生新的String對象。String特性主要有兩點绒净。1见咒,不可變:不可變的主要作用在于當一個對象需要被多線程共享,并且訪問頻繁時挂疆,可以省略同步和鎖等待的時間改览,從而大幅度提高系統(tǒng)性能。不可變模式是一個可以提高多線程程序的性能缤言,降低多線程程序復(fù)雜度的設(shè)計模式宝当。2,常量池的優(yōu)化:當2個String對象擁有相同的值時胆萧,他們只引用常量池中的同一個拷貝庆揩。當同一個字符串反復(fù)出現(xiàn)時,這個技術(shù)可以大幅度節(jié)省內(nèi)存空間跌穗。
????????StringBuffer是為了解決String拼接產(chǎn)生太多中間對象的問題而提供的一個類订晌。StringBuffer本質(zhì)是一個線程安全的可修改字符串序列,它保證了線程安全蚌吸,也隨之帶來了額外的性能開銷锈拨。
????????StringBuild是jdk1.5中新增的,在能力上和StringBuffer沒有本質(zhì)區(qū)別套利,但是它去掉了線程安全的部分推励,有效減小了開銷鹤耍。
????????為了實現(xiàn)修改字符串序列的目的,StringBuffer和StringBuild底層都是利用了可修改的(char,JDK9以后是byte)數(shù)組验辞,二者都繼承了AbstractStringBuilder,里面包含了基本操作稿黄,區(qū)別僅在于最終方法是否加了synchronized。它們內(nèi)部構(gòu)建初始化數(shù)組長度是16跌造,長度大于16時會自動擴容杆怕,需要拋棄原有數(shù)據(jù)創(chuàng)建新(可以簡單認為是倍數(shù))的數(shù)組,還要進行arraycopy壳贪。所以我們可以根據(jù)字符長度傳入初始化的合適長度陵珍,避免多次擴容的開銷。除非有線程安全考慮建議使用StringBuild违施。
第二互纯,String的創(chuàng)建機理和應(yīng)用場景
? ? ? ? 創(chuàng)建機理:由于String在Java世界中使用過于頻繁,Java為了避免在一個系統(tǒng)中產(chǎn)生大量的String對象磕蒲,引入了字符串常量池留潦。其運行機制是:創(chuàng)建一個字符串時,首先檢查池中是否有值相同的字符串對象辣往,如果有則不需要創(chuàng)建直接從池中剛查找到的對象引用兔院;如果沒有則新建字符串對象,返回對象引用站削,并且將新創(chuàng)建的對象放入池中坊萝。但是,通過new方法創(chuàng)建的String對象是不檢查字符串池的许起,而是直接在堆區(qū)或棧區(qū)創(chuàng)建一個新的對象十偶,也不會把對象放入池中。上述原則只適用于通過直接量給String對象引用賦值的情況街氢。舉例:
? ? ? ? String str1 = "hello,world"; //通過直接量賦值方式扯键,放入字符串常量池睦袖。
? ? ? ? String str2 = new String(“hello,world”);//通過new方式賦值方式珊肃,不放入字符串常量池。
????????注意:String提供了inter()方法馅笙。調(diào)用該方法時伦乔,如果常量池中包括了一個等于此String對象的字符串(由equals方法確定),則返回池中的字符串董习。否則烈和,將此String對象添加到池中,并且返回此池中對象的引用皿淋。
? ??????應(yīng)用場景:在字符串內(nèi)容不經(jīng)常發(fā)生變化的業(yè)務(wù)場景優(yōu)先使用String類招刹。例如:常量聲明恬试、少量的字符串拼接操作等。如果有大量的字符串內(nèi)容拼接疯暑,避免使用String與String之間的“+”操作训柴,因為這樣會產(chǎn)生大量無用的中間對象,耗費空間且執(zhí)行效率低下(新建對象妇拯、回收對象花費大量時間)幻馁。
第三,輕松理解String.intern()
????????該方法的總結(jié)參考《深入理解Java虛擬機》一書越锈。
????????1仗嗦,new String都是在堆上創(chuàng)建字符串對象。當調(diào)用 intern() 方法時甘凭,編譯器會將字符串添加到常量池中(stringTable維護)稀拐,并返回指向該常量的引用。?JDK1.8后字符串常量池放到了堆中丹弱,不再是在方法區(qū)中了钩蚊。
????????2,通過字面量賦值創(chuàng)建字符串(如:String str=”twm”)時蹈矮,會先在常量池中查找是否存在相同的字符串砰逻,若存在,則將棧中的引用直接指向該字符串泛鸟;若不存在蝠咆,則在常量池中生成一個字符串,再將棧中的引用指向該字符串北滥。
????????3刚操,常量字符串的“+”操作,編譯階段直接會合成為一個字符串再芋。如string str=”JA”+”VA”菊霜,在編譯階段會直接合并成語句String str=”JAVA”,于是會去常量池中查找是否存在”JAVA”,從而進行創(chuàng)建或引用济赎。
????????4鉴逞,對于final字段,編譯期直接進行了常量替換(而對于非final字段則是在運行期進行賦值處理的)司训。
????????5勾徽,常量字符串和變量拼接時(如:String str3=baseStr + “01”;)會調(diào)用stringBuilder.append()在堆上創(chuàng)建新的對象。
????????6统扳,JDK 1.7后喘帚,intern方法還是會先去查詢常量池中是否有已經(jīng)存在畅姊,如果存在,則返回常量池中的引用吹由,這一點與之前沒有區(qū)別涡匀,區(qū)別在于,如果在常量池找不到對應(yīng)的字符串溉知,則不會再將字符串拷貝到常量池陨瘩,而只是在常量池中生成一個對原字符串的引用。簡單的說级乍,就是往常量池放的東西變了:原來在常量池中找不到時舌劳,復(fù)制一個副本放到常量池,1.7后則是將在堆上的地址引用復(fù)制到常量池玫荣。
舉例說明:
第四,String使用equals和==比較的區(qū)別捅厂?
????????“==”操作符的作用:1贯卦,用于基本數(shù)據(jù)類型的比較。2焙贷,判斷引用是否指向堆內(nèi)存的同一塊地址撵割。
????????equals的作用:用于判斷兩個變量是否是對同一個對象的引用,即堆中的內(nèi)容是否相同辙芍,返回值為布爾類型
????????結(jié)論:1啡彬,對象不同,內(nèi)容相同故硅,"=="返回false庶灿,equals返回true。2吃衅,同一對象往踢,"=="和equals結(jié)果相同
我是溫馭臣徘层,一個Android開發(fā)者峻呕,以上是我的簡單總結(jié),如果有缺陷惑灵,希望在評論區(qū)看到您的補充山上。