最近在掃描CodeDex時報了一個不能使用String.intern()的字符串來作鎖對象的告警,對這個問題有疑問查了些資料,順便學習一下String類的源碼。java
1.類定義 String 被final修飾,是葉子類,不能不繼承。實現了Serializable,Comparable,CharSequence 接口正則表達式
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {...}
Serializable:實現此接口來支持序列化和反序列化,Java的序列化機制是經過在運行時判斷類的serialVersionUID來驗證版本一致性的數組
Comparable:實現此接口的對象列表(和數組)能夠經過 Collections.sort (和 Arrays.sort )進行自動排序函數
CharSequence:字符序列,String本質是經過字符數組實現的學習
2.屬性ui
2.1 value final的數組,用來儲存String對象的字符this
2.2 hash String對象的HashCodespa
2.3 serialPersistentFields ?在序列化流協議中String類會被特別包裝,String對象會被寫入到一個ObjectOutputStream...code
3.構造方法orm
3.1 無參數構造方法默認返回空的字符串,由於String是不可變的,全部沒有必要使用此構造函數
1 public String() { 2 this.value = "".value; 3 }
3.2
1 public String(String original) { 2 this.value = original.value; 3 this.hash = original.hash; 4 }
3.3
1 public String(char value[]) { 2 this.value = Arrays.copyOf(value, value.length); 3 }
3.4
public String(byte bytes[]) {//用默認的charset進行decode this(bytes, 0, bytes.length); } public String(byte bytes[], int offset, int length) { checkBounds(bytes, offset, length); this.value = StringCoding.decode(bytes, offset, length); } public String(byte bytes[], int offset, int length, Charset charset) { if (charset == null) throw new NullPointerException("charset"); checkBounds(bytes, offset, length); this.value = StringCoding.decode(charset, bytes, offset, length); }
3.5 把此String對象的字符copy到dst數組,dst數組中從dstBegin的位置開始放置,此方法不進行任何邊界校驗
void getChars(char dst[], int dstBegin) { System.arraycopy(value, 0, dst, dstBegin, value.length); }
3.6 比較此對象從toffset位置的len長度字符數組是否和other對象的ooffset位置的len長度字符數組是同一個數組
/* *比較本對象從toffset位置開始的len長度的char數組是否和other對象的ooffset位置開始的len長度的char數組是同一個數組 */ public boolean regionMatches(int toffset, String other, int ooffset, int len) {...} /* *帶boolean參數的表示是否忽略大小寫 */ public boolean regionMatches(boolean ignoreCase, int toffset, String other, int ooffset, int len) {...} /* *在equalsIgnoreCase方法中調用了帶boolean參數的regionMatches */ public boolean equalsIgnoreCase(String anotherString) { ... }
3.7 是否以特定的字符串開頭和結尾
public boolean startsWith(String prefix, int toffset) {...} public boolean endsWith(String suffix) {...}//endsWith調用的startsWith
3.8 indexOf系列
3.9
public String substring(int beginIndex) {...}
3.10 concat() 本對象以後鏈接字符串,返回新生成新的字符串
public String concat(String str) { int otherLen = str.length(); if (otherLen == 0) { return this; } int len = value.length; char buf[] = Arrays.copyOf(value, len + otherLen); str.getChars(buf, len); return new String(buf, true); }
3.11 校驗字符串是否符合正則表達式
public boolean matches(String regex) {...}
3.12 delimiter作鏈接符鏈接字符串列表或數組
public static String join(CharSequence delimiter, CharSequence... elements) { Objects.requireNonNull(delimiter); Objects.requireNonNull(elements); // Number of elements not likely worth Arrays.stream overhead. StringJoiner joiner = new StringJoiner(delimiter); for (CharSequence cs: elements) { joiner.add(cs); } return joiner.toString(); }
e.g.
public static void main(String[] args) { List<String> names=new ArrayList<String>(); names.add("1"); names.add("2"); names.add("3"); System.out.println(String.join("-", names)); String[] arrStr=new String[]{"a","b","c"}; System.out.println(String.join("-", arrStr)); }
輸出:
3.13 去除字符串先後空格返回生成的新的子字符串
public String trim() {...}
3.14 格式化字符串
3.14.1 方法簽名
public static String format(String format, Object... args) {...}
3.14.2 轉換符
說 明 |
示 例 |
|
%s |
字符串類型 |
"mingrisoft" |
%c |
字符類型 |
'm' |
%b |
布爾類型 |
true |
%d |
整數類型(十進制) |
99 |
%x |
整數類型(十六進制) |
FF |
%o |
整數類型(八進制) |
77 |
%f |
浮點類型 |
99.99 |
%a |
十六進制浮點類型 |
FF.35AE |
%e |
指數類型 |
9.38e+5 |
%g |
通用浮點類型(f和e類型中較短的) |
|
%h |
散列碼 |
|
%% |
百分比類型 |
% |
%n |
換行符 |
|
%tx |
日期與時間類型(x表明不一樣的日期與時間轉換符 |
3.14.3 e.g.
System.out.println(String.format("如今的時間是:%d-%d-%d %d:%d:%d",2011,1,2,15,29,30));
輸出結果:
3.15 valueOf
public static String valueOf(Object obj) { return (obj == null) ? "null" : obj.toString(); }
3.16 String類私有維護的String pool 初始化時是空的,當對象s調用intern方法時,若是pool中已存在與之equals爲true的t對象,那麼池中存在的t對象會被返回,不然新的String對象會被加入到pool中,而後返回這個String對象的引用。
此得出結論:只要s.equals(t),s.intern() == t.intern() 爲true
public native String intern();
當使用String s = "abc"方式建立字符串時,字符串會自動加入常量池,而當使用String s = new String("abc")方式建立時,只有調用了s.intern()方法纔會把s加入常量池
String pool default size:
7u40以前:1009,
7u40+ to 8:60013
java6的時候存在PermGen區,容易形成oom,java7以後改成存在Heap區
7u02以後能夠用-XX:StringTableSize=100003 設置JVM參數
(參考http://java-performance.info/string-intern-in-java-6-7-8/)