不知道你們有沒有這樣得經歷,就是無心中點進去得一個業面,而後鑽到裏面瀏覽了很久,我就是這樣得,今天無心中,ctrl+左鍵,就點進了string得源碼,正好今天下午沒啥事,就在裏面看一下,沒想到,下次緩過來,就是我同事拍我讓我去吃飯,哈哈哈哈,不過好處就是,我這邊也整理了一些string類得知識點,也分享給你們,整理得很差還望海涵
文章首發我的公衆號:Java架構師聯盟,每日更新技術好文
1、String類
想要了解一個類,最好的辦法就是看這個類的實現源代碼,來看一下String類的源碼:
public final class Stringjava
implements java.io.Serializable, Comparable<String>, CharSequence{ /** The value is used for character storage. */ private final char value[]; /** The offset is the first index of the storage that is used. */ private final int offset; /** The count is the number of characters in the String. */ private final int count; /** Cache the hash code for the string */ private int hash; // Default to 0 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; ........
}
從上面能夠看出幾點:
1)String類是final類,也即意味着String類不能被繼承,而且它的成員方法都默認爲final方法。在Java中,被final修飾的類是不容許被繼承的,而且該類中的成員方法都默認爲final方法。
2)上面列舉出了String類中全部的成員屬性,從上面能夠看出String類實際上是經過char數組來保存字符串的。
下面再繼續看String類的一些方法實現:
public String substring(int beginIndex, int endIndex) {數組
if (beginIndex < 0) { throw new StringIndexOutOfBoundsException(beginIndex); } if (endIndex > count) { throw new StringIndexOutOfBoundsException(endIndex); } if (beginIndex > endIndex) { throw new StringIndexOutOfBoundsException(endIndex - beginIndex); } return ((beginIndex == 0) && (endIndex == count)) ? this : new String(offset + beginIndex, endIndex - beginIndex, value);
}
public String concat(String str) {架構
int otherLen = str.length(); if (otherLen == 0) { return this; } char buf[] = new char[count + otherLen]; getChars(0, count, buf, 0); str.getChars(0, otherLen, buf, count); return new String(0, count + otherLen, buf);
}
public String replace(char oldChar, char newChar) {jvm
if (oldChar != newChar) { int len = count; int i = -1; char[] val = value; /* avoid getfield opcode */ int off = offset; /* avoid getfield opcode */ while (++i < len) { if (val[off + i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0 ; j < i ; j++) { buf[j] = val[off+j]; } while (i < len) { char c = val[off + i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(0, len, buf); } } return this;
}
從上面的三個方法能夠看出,不管是sub操、concat仍是replace操做都不是在原有的字符串上進行的,而是從新生成了一個新的字符串對象。也就是說進行這些操做後,最原始的字符串並無被改變。
在這裏要永遠記住一點:「String對象一旦被建立就是固定不變的了,對String對象的任何改變都不影響到原對象,相關的任何change操做都會生成新的對象」。
2、字符串常量池
咱們知道字符串的分配和其餘對象分配同樣,是須要消耗高昂的時間和空間的,並且字符串咱們使用的很是多。JVM爲了提升性能和減小內存的開銷,在實例化字符串的時候進行了一些優化:使用字符串常量池。每當咱們建立字符串常量時,JVM會首先檢查字符串常量池,若是該字符串已經存在常量池中,那麼就直接流量交易返回常量池中的實例引用。若是字符串不存在常量池中,就會實例化該字符串而且將其放到常量池中。因爲String字符串的不可變性咱們能夠十分確定常量池中必定不存在兩個相同的字符串(這點對理解上面相當重要)。
Java中的常量池,實際上分爲兩種形態:靜態常量池和運行時常量池。 所謂靜態常量池,即*.class文件中的常量池,class文件中的常量池不只僅包含字符串(數字)字面量,還包含類、方法的信息,佔用class文件絕大部分空間。 而運行時常量池,則是jvm虛擬機在完成類裝載操做後,將class文件中的常量池載入到內存中,並保存在方法區中,咱們常說的常量池,就是指方法區中的運行時常量池。
來看下面的程序:
String a = "chenssy";String b = "chenssy";
a、b和字面上的chenssy都是指向JVM字符串常量池中的"chenssy"對象,他們指向同一個對象。
String c = new String("chenssy");
new關鍵字必定會產生一個對象chenssy(注意這個chenssy和上面的chenssy不一樣),同時這個對象是存儲在堆中。因此上面應該產生了兩個對象:保存在棧中的c和保存堆中chenssy。可是在Java中根本就不存在兩個徹底如出一轍的字符串對象。故堆中的chenssy應該是引用字符串常量池中chenssy。因此c、chenssy、池chenssy的關係應該是:c--->chenssy--->池chenssy。性能