String 類實(shí)現(xiàn)了 Serializable 和 Comparable 接口,采用 final 關(guān)鍵字修飾,不能被繼承。其內(nèi)部是以一個(gè) final 修飾的字符數(shù)組的形式組織存儲(chǔ)字符的,JDK 源碼如下:private final char[] value;以后看到字符串對(duì)象,就想著它是一個(gè)字符數(shù)組對(duì)象,當(dāng)成一個(gè)數(shù)組看待哦,它本質(zhì)也就是一個(gè)數(shù)組啊。
String 類對(duì)象的只讀性
可以說(shuō),String 字符串對(duì)象本質(zhì)上是一個(gè) final 修飾的字符串?dāng)?shù)組對(duì)象,只是因?yàn)樽址@種東西用的太廣泛了,所以在它的基礎(chǔ)上封裝了諸多方法,提供給客戶端程序員使用的一個(gè)字符串工具類。這也就是通常意義上所說(shuō)的 String 類型對(duì)象具有不可變性,因?yàn)?final 類型的字符串?dāng)?shù)組對(duì)象一旦創(chuàng)建,就不再能被改變。其他對(duì)已有的字符串對(duì)象的操作,看似在改變了當(dāng)前對(duì)象,其實(shí)都是重新開(kāi)辟了一個(gè)內(nèi)存空間,產(chǎn)生了一個(gè)新的字符串對(duì)象。原有的字符串對(duì)象仍然安靜的存在,并沒(méi)有任何改變。Java 中就是這樣對(duì)待字符串的,對(duì)字符串一點(diǎn)都不吝嗇內(nèi)存空間。
創(chuàng)建對(duì)象的三種方式,及其在內(nèi)存中的分布
創(chuàng)建對(duì)象有三種方式
- 直接賦值:
String s = "keqi" - 使用 new 關(guān)鍵字:
String s = new String("keqi") - 使用字符串連接符 ‘+’ :
String s = "keqi" + "is so cool";
第一種方式使用的是String s1 = "keqi";String s2 = "keqi";,這會(huì)直接在常量數(shù)據(jù)區(qū)開(kāi)辟對(duì)象內(nèi)存空間。首先檢查常量數(shù)據(jù)區(qū)中是否有相同的對(duì)象,如果有則直接指向這個(gè)對(duì)象,沒(méi)有就創(chuàng)建。所以,采用 == 判斷兩個(gè)字符串同值的對(duì)象得到結(jié)果為 true。
第二種方式使用的是String s3 = new String("keqi");String s4 = new String("keqi");,這會(huì)首先在常量區(qū)中開(kāi)辟對(duì)應(yīng)的內(nèi)存空間,然后再在堆區(qū)開(kāi)辟對(duì)象內(nèi)存空間,但是以后操作的都是堆區(qū)的這個(gè)內(nèi)存空間。所以,采用 == 判斷兩個(gè)字符串同值的對(duì)象得到結(jié)果為 false。至于為什么要這樣設(shè)計(jì)呢?為了后期使用上的效率嗎?以空間換時(shí)間吧。
第三種采用字符串連接符+創(chuàng)建對(duì)象的方式,也是在常量數(shù)據(jù)區(qū)開(kāi)辟空間后,再在堆區(qū)開(kāi)辟一個(gè)內(nèi)存空間。以后使用的也是堆區(qū)的那個(gè)內(nèi)存對(duì)象,這和用 new 的方式創(chuàng)建對(duì)象是一樣的。
以上在 6.21 號(hào)上課的源碼中有詳細(xì)證明。
String 的 hashCode() 方法和 equals() 方法
Object 的 hashCode() 方法是沒(méi)有實(shí)現(xiàn)的,equals() 方法又是直接使用 == 判斷。一般 Object 子類重寫了 equals() 方法,就要去重寫 hashCode() 方法,因?yàn)楸仨氁WC equals() 相同,hashcode() 也要想通,為什么要這樣?凡是以后自定義類需要重寫 equals() 方法的,都記得這樣做。以后實(shí)際用到了,再來(lái)解決這個(gè)疑問(wèn)吧。
最初接觸哈希值的概念是在數(shù)據(jù)結(jié)構(gòu)當(dāng)中學(xué)習(xí)散列表的時(shí)候,哈希算法計(jì)算出來(lái)的哈希值是為了減少碰撞,快速定位,能夠利用這種數(shù)據(jù)結(jié)構(gòu)更快速的查找和存儲(chǔ)對(duì)象。Java 集合框架中的 HashMap 、HashSet 的底層數(shù)據(jù)結(jié)構(gòu)就是散列表。Object 類有一個(gè)名為 hashCode() 的抽象方法,每一個(gè)子類都必須實(shí)現(xiàn)這個(gè)方法,這是為了支持散列表存儲(chǔ)而專門設(shè)置的。
String 類實(shí)現(xiàn)了 hashCode() 方法,其哈希算法計(jì)算規(guī)則如下s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1],也就是按照每個(gè)字符對(duì)應(yīng)的 ascii 十進(jìn)制的數(shù)據(jù)代入上述公式計(jì)算,最終得出的結(jié)果就是哈希值。明白了 String 類的哈希值計(jì)算方式,就明白了指向同一塊內(nèi)存空間的兩個(gè)變量的哈希值肯定相同,但是哈希值相同,并不代表是同一個(gè)對(duì)象,可能只是因?yàn)樗膬?nèi)容剛好相同。
Integer 類也實(shí)現(xiàn)了 hashCode() 方法,它是直接返回了存儲(chǔ)的 value 值,作為哈希值,自然也已經(jīng)重寫了 equals() 方法。
String類常見(jiàn)的方法
以后用到了,慢慢積累吧,必須要積累,因?yàn)檫@顯得你專業(yè),如果用到了還需要去查詢的話,顯得你不夠老練哦。