String詳解:java
(1)String不屬於基本數據類型,Stirng是一個對象 (2)String類被final修飾,不能夠被 (3)String能夠經過「+「鏈接 (4)String類的本質是char[] (5)String運行時維護常量池
(1)類的定義: public final class String implements java.io.Serializable, Comparable<String>, CharSequence { (2)主要屬性(GDK1.6): private final char value[]; //String本質就是Char數組 private final int offset; //偏移位 private final int count; //就是Sting的length private int hash; //hash碼
簡單的理解: 若變量是基本類型則值不變 若變量是引用類型則引用不變 String內部變量是被Final修飾的,對String的改變不能將原來的String改變,只能從新返回一個新的String。這是String與其餘普通對象的重要區別。
經過源碼理解"對String的改變不能將原來的String改變,只能從新返回一個新的String"這句話。數組
public String(char value[], int offset, int count) { if (offset < 0) { throw new StringIndexOutOfBoundsException(offset); } if (count <= 0) { if (count < 0) { throw new StringIndexOutOfBoundsException(count); } if (offset <= value.length) { this.value = "".value; return; } } // Note: offset or count might be near -1>>>1. if (offset > value.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } this.value = Arrays.copyOfRange(value, offset, offset+count); } public static char[] copyOfRange(char[] original, int from, int to) { int newLength = to - from; if (newLength < 0) throw new IllegalArgumentException(from + " > " + to); char[] copy = new char[newLength];//建立新的數組對象 System.arraycopy(original, from, copy, 0, Math.min(original.length - from, newLength)); return copy; }
replace方法咱們會誤覺得會發生值的改變,以下this
String str = 「123」, str = str.replace('1','a'), 咱們會誤認爲a的值發生改變,查看源碼發現其實建立了一個新對象,而後讓str指向這個對象。spa
//源碼 public String replace(char oldChar, char newChar) { if (oldChar != newChar) { int len = value.length; int i = -1; char[] val = value; /* avoid getfield opcode */ while (++i < len) { if (val[i] == oldChar) { break; } } if (i < len) { char buf[] = new char[len]; for (int j = 0; j < i; j++) { buf[j] = val[j]; } while (i < len) { char c = val[i]; buf[i] = (c == oldChar) ? newChar : c; i++; } return new String(buf, true);//建立新的對象 } } return this; }
(1)new建立 String str = new String(「123「); 此方式必定會在堆區建立一個新對象,使用String類的intern()方法能夠將其放入常量池。 (ps:java不要求常量必定在編譯期才能產生) (2)直接指定 String str = 「123」; 對象建立時先查看常量池,常量池中存在就不建立,不存在時建立新對象而且放入常量池。 (3)使用「+」 String str = 「12」 + 「3」; 使用直接指定或者使用純字符串來建立時,先檢查常量池。若是存在則不建立,不存在時建立新對象而且放入常量池。 (4) String str2 = "12"; String str7 = str2 + "1"; 使用包含變量的表達式來建立時不檢查常量池。
public class StringTest { public static void main(String[] args) { //new建立 String str1 = new String("123"); //直接指定 String str2 = "123"; System.out.println(str1 == str2);//false //使用 "+" String str3 = "12" + "3"; System.out.println(str2 == str3);//true //使用包含變量的表達式來建立 String str4 = new String("12"); String str5 = str4 + "3"; System.out.println(str5 == str2);//false //使用包含變量的表達式來建立 String str6 = "12"; String str7 = "3"; String str8 = str6 + str7; System.out.println(str8 == str2);//false } }
String對象真的是不可變的嗎?其實咱們能夠使用反射機制改變,例子以下:code
public class StringReflection { public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException { String str = "123"; System.out.println(str); //123 Field valueFiled = String.class.getDeclaredField("value"); //訪問屬性設置 valueFiled.setAccessible(true); char[] oldValue = (char[]) valueFiled.get(str); oldValue[0] = 'A'; System.out.println(str); //A123 } }