Java String 小總結

1.String是不可變類

不可變類呢?一般認為:當對象一旦創(chuàng)建完成后,在正常情況下浮声,對象的狀態(tài)不會因外界的改變而改變(對象的狀態(tài)是指對象的屬性虚婿,包括屬性的類型及屬性值)。

首先看一個基本的例子:

1String s = "abc";2System.out.println("s:" + s);//輸出s:abc3s = "def";4System.out.println("s:" + s);//輸出s:def

s只是指向堆內存中的引用泳挥,存儲的是對象在堆中的地址然痊,而非對象本身,s本身存儲在棧內存中屉符。實際上剧浸,此時堆內存中依然存在著"abc"和"def"對象。對于"abc"對象本身而言矗钟,對象的狀態(tài)是沒有發(fā)生任何變化的唆香。(對象不可變)

既然不可變說明String類中肯定沒有提供對外可setters方法。接下來來具體看一下String類的定義吨艇。

1publicfinalclassStringimplementsjava.io.Serializable, Comparable

, CharSequence{23/**The value is used for character storage.*/4privatefinalcharvalue[];56/**Cache the hash code for the string*/7privateinthash;//Default to 089}

與之前版本的Java String源碼相比躬它,String類減少了int offset 和 int count的定義。這樣變化的結果主要體現在:

1.避免之前版本的String對象subString時可能引起的內存泄露問題东涡;

2.新版本的subString時間復雜度將有O(1)變?yōu)镺(n);

通過上面String類的定義冯吓,類名前面用了final class修飾倘待,因此,String類不能被繼承组贺。對于其屬性定義凸舵,可以看出,屬性value[]和hash都是被定義成private類型失尖,且由于沒有提供對外的public setters方法啊奄,String類屬性不可被改變。

其中雹仿,需要重點關注屬性value[]增热,其被final char修飾,因此字符型數組value只會被賦值一次就不可修改胧辽。其存儲內容正好是String中的單個字符內容峻仇。

2.String相關的 +

String中的 + 常用于字符串的連接。此處為了說明清楚這個問題邑商,首先可以安裝Eclipse 查看字節(jié)碼插件ByteCode Outline摄咆。

在線安裝網址:http://zipeditor.sourceforge.net/update/Disabled。Help >> install new software >> 輸入網址 >> 選擇 bytecode outline >> ... ... 安裝成功人断。

Window >> show view >> other >> java >> ByteCode即可在Eclipse下方面板欄中查看吭从。

1publicstaticmain([Ljava/lang/String;)V2L03LINENUMBER 5L04LDC "aa"5ASTORE 16L17LINENUMBER 6L18LDC "bb"9ASTORE 210L211LINENUMBER 7L212NEW java/lang/StringBuilder13DUP14

LDC "xxyy "

15INVOKESPECIAL java/lang/

StringBuilder.

(Ljava/lang/String;)V16ALOAD 117INVOKEVIRTUAL java/lang/

StringBuilder.append

(Ljava/lang/String;)Ljava/lang/StringBuilder;18

LDC "zz"

19INVOKEVIRTUAL java/lang/

StringBuilder.append

(Ljava/lang/String;)Ljava/lang/StringBuilder;20

LDC "mm"

21INVOKEVIRTUAL java/lang/

StringBuilder.append

(Ljava/lang/String;)Ljava/lang/StringBuilder;22ALOAD 223INVOKEVIRTUAL java/lang/

StringBuilder.append

(Ljava/lang/String;)Ljava/lang/StringBuilder;24INVOKEVIRTUAL java/lang/

StringBuilder.toString

()Ljava/lang/String;25ASTORE 326L327LINENUMBER 8L328GETSTATIC java/lang/System.out : Ljava/io/PrintStream;29ALOAD 330INVOKEVIRTUAL java/io/PrintStream.println (Ljava/lang/String;)V31L432LINENUMBER 9L433RETURN34L535LOCALVARIABLE args [Ljava/lang/String; L0 L5 036LOCALVARIABLE a Ljava/lang/String; L1 L5 137LOCALVARIABLE b Ljava/lang/String; L2 L5 238LOCALVARIABLE c Ljava/lang/String; L3 L5 339MAXSTACK = 340MAXLOCALS = 441}

顯然,通過字節(jié)碼我們可以得出如下幾點結論:

1.String中使用 + 字符串連接符進行字符串連接時恶迈,連接操作最開始時如果都是字符串常量涩金,編譯后將盡可能多的直接將字符串常量連接起來,形成新的字符串常量參與后續(xù)連接(通過反編譯工具jd-gui也可以方便的直接看出)暇仲;

2.接下來的字符串連接是從左向右依次進行步做,對于不同的字符串,首先以最左邊的字符串為參數創(chuàng)建StringBuilder對象奈附,然后依次對右邊進行append操作全度,最后將StringBuilder對象通過toString()方法轉換成String對象(注意:中間的多個字符串常量不會自動拼接)

也就是說

String c = "xx" + "yy " + a + "zz" + "mm" + b; 實質上的實現過程是: String c =?new StringBuilder("xxyy").append(a).append("zz").append("mm").append(b).toString();

由于得出結論:當使用+進行多個字符串連接時斥滤,實際上是產生了一個StringBuilder對象和一個String對象将鸵。

3.String中的常用方法

1).與String類中value[]數組存儲直接相關的有:

int length(); // 返回String長度,亦即value[]數組長度佑颇;

char charAt(int index); // 返回指定位置字符顶掉;

int indexOf(int ch, int fromIndex); //從fromIndex位置開始,查找ch字符在字符串中首次出現的位置挑胸。fromIndex默認為0一喘,ch直接傳入字符即可。如'C',區(qū)分大小寫凸克,未查找到返回-1议蟆;

char[] toCharArray() ; ? // 將字符串轉換成一個新的字符數組

2).與其他字符串即字串相關的方法有:

int indexOf(String str, int fromIndex) ;

與indexOf含義相反有l(wèi)astIndexOf(..),反向索引萎战。

boolean contains(String str); //實際上 contains內部實現也是調用的indexOf咐容,然后將其結果與-1相比較。

boolean?startsWith(String str); // 判斷字符串是否以str開頭

boolean endsWith(String str); //.....是否以str結尾

String replace(CharSequence target, CharSequence replacement) ; ?// 替換

String substring(int beginIndex, ?int endIndex); ?//字符串截取蚂维,不傳第二個參數則表示直接截取到字符串末尾

String[] split(String regex); ?// 字符串分割

4.String中的equals()與hashCode() equals重寫 hashcode重寫

String類重寫了Object類的equlas方法戳粒,使得比較字符串內容是否相等可以直接使用equlas方法。關于equals以及相應的hashCode方法參見博文《Java總結篇系列:java.lang.Object?》

5.String字符串常量池

JVM為了提高性能和減少內存開銷虫啥,內部維護了一個字符串常量池蔚约,每當創(chuàng)建字符串常量時,JVM首先檢查字符串常量池涂籽,如果常量池中已經存在苹祟,則返回池中的字符串對象引用,否則創(chuàng)建該字符串對象并放入池中评雌。

因此下述結果返回true树枫。

1String a = "abc";2String b = "abc";3System.out.print(a == b);//true

但與創(chuàng)建字符串常量方式不同的是,當使用new String(String str)方式等創(chuàng)建字符串對象時景东,不管字符串常量池中是否有與此相同內容的字符串砂轻,都會在堆內存中創(chuàng)建新的字符串對象。

因此斤吐,下面代碼片段有如下結果搔涝。

1String a = "Hello";2String b =newString("Hello");3System.out.println(a == b);//false4System.out.println(a.equals(b));//true

即使字符串內容相同,字符串常量池中的字符串與通過new String(..)等方式創(chuàng)建的字符串對象之間沒有直接的關系和措,但是庄呈,可以通過字符串的intern()方法找到此種關聯。intern()方法返回字符串對象在字符串常量池中的對象引用臼婆,若字符串常量池中尚未有此字符串,則創(chuàng)建一新的字符串常量放置于池中幌绍。

于是颁褂,很據如上理解,很自然的傀广,可以得到如下結果颁独。1String a = "Hello";2System.out.println(a == a.intern());//true34String b =newString("corn");5String c =b.intern();67System.out.println(b == c);//false89String d = "corn";1011System.out.println(c == d);//true

6.String/StringBuilder/StringBuffer區(qū)別

String是不可變字符串對象,StringBuilder和StringBuffer是可變字符串對象(其內部的字符數組長度可變)伪冰,StringBuffer線程安全誓酒,StringBuilder非線程安全。

7.既然String是不可變字符串對象,如何才能改變讓其可變?

既然String對象中沒有對外提供可用的public setters等方法靠柑,因此只能通過Java中的反射機制實現寨辩。因此,前文中說到的String是不可變字符串對象只是針對“正常情況下”歼冰。而非必然靡狞。

1publicstaticvoidstringReflection()throwsException {23String s = "Hello World";45System.out.println("s = " + s);//Hello World67//獲取String類中的value字段8Field valueField = String.class.getDeclaredField("value");910//改變value屬性的訪問權限11valueField.setAccessible(true);1213char[] value = (char[]) valueField.get(s);1415//改變value所引用的數組中的第5個字符16value[5] = '_';1718System.out.println("s = " + s);//Hello_World19}

由此可見Java中反射的強大之處。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末隔嫡,一起剝皮案震驚了整個濱河市甸怕,隨后出現的幾起案子,更是在濱河造成了極大的恐慌腮恩,老刑警劉巖梢杭,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異秸滴,居然都是意外死亡武契,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門缸榛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來吝羞,“玉大人,你說我怎么就攤上這事内颗【牛” “怎么了?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵均澳,是天一觀的道長恨溜。 經常有香客問我,道長找前,這世上最難降的妖魔是什么糟袁? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮躺盛,結果婚禮上项戴,老公的妹妹穿的比我還像新娘。我一直安慰自己槽惫,他們只是感情好周叮,可當我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著界斜,像睡著了一般仿耽。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上各薇,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天项贺,我揣著相機與錄音,去河邊找鬼。 笑死开缎,一個胖子當著我的面吹牛棕叫,可吹牛的內容都是我干的。 我是一名探鬼主播啥箭,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼谍珊,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了急侥?” 一聲冷哼從身側響起砌滞,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坏怪,沒想到半個月后贝润,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡铝宵,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年打掘,在試婚紗的時候發(fā)現自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片鹏秋。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡尊蚁,死狀恐怖,靈堂內的尸體忽然破棺而出侣夷,到底是詐尸還是另有隱情横朋,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布百拓,位于F島的核電站琴锭,受9級特大地震影響,放射性物質發(fā)生泄漏衙传。R本人自食惡果不足惜决帖,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蓖捶。 院中可真熱鬧地回,春花似錦、人聲如沸俊鱼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亭引。三九已至绎速,卻和暖如春皮获,著一層夾襖步出監(jiān)牢的瞬間焙蚓,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留饼丘,地道東北人溜在。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓数苫,卻偏偏與公主長得像,于是被迫代替她去往敵國和親知残。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內容

  • 1. Java基礎部分 基礎部分的順序:基本語法比庄,類相關的語法求妹,內部類的語法,繼承相關的語法佳窑,異常的語法制恍,線程的語...
    子非魚_t_閱讀 31,644評論 18 399
  • 1. Java中的多態(tài)性理解(注意與C++區(qū)分) Java中除了static方法和final方法(private方...
    小敏紙閱讀 1,443評論 0 19
  • 一净神、JVM內幕:Java虛擬機詳解(java se 7規(guī)范) 直接上圖,再逐步解釋溉委。 上圖顯示的組件分兩個章節(jié)解釋...
    屈小勇閱讀 1,848評論 6 22
  • 這篇文章解釋了Java 虛擬機(JVM)的內部架構鹃唯。下圖顯示了遵守Java SE 7 規(guī)范的典型的 JVM 核心內...
    飲墨饗書閱讀 663評論 0 1
  • 旅途總是那么奇妙,在一段段故事中瓣喊,相遇坡慌,相聚,最終相離型宝,而那份情誼則在心底回蕩八匠。 看完《毛騙》終章,心里存在很多思...
    單反時光閱讀 279評論 0 0