免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項超值服

開通VIP
Java String源碼解析

String類概要

  • 所有的字符串字面量都屬于String類,String對象創(chuàng)建后不可改變,因此可以緩存共享,StringBuilder,StringBuffer是可變的實現(xiàn)
  • String類提供了操作字符序列中單個字符的方法,比如有比較字符串,搜索字符串等
  • Java語言提供了對字符串連接運(yùn)算符的特別支持(+),該符號也可用于將其他類型轉(zhuǎn)換成字符串。
  • 字符串的連接實際上是通過StringBuffer或者StringBuilder的append()方法來實現(xiàn)的
  • 一般情況下,傳遞一個空參數(shù)在這類構(gòu)造函數(shù)或方法會導(dǎo)致NullPointerException異常被拋出。
  • String表示一個字符串通過UTF-16(unicode)格式,補(bǔ)充字符通過代理對表示。索引值參考字符編碼單元,所以補(bǔ)充字符在String中占兩個位置。

String是不可變的

  • String是常量,一旦被創(chuàng)建就不可被改變,因此可以用來共享

從String的怪異現(xiàn)象講起

String是否相等

==判斷的是對象的內(nèi)存起始地址是否相同,equals判斷自定義的語義是否相同

  • JVM為了提高內(nèi)存效率,將所有不可變的字符串緩存在常量池中,當(dāng)有新的不可變的字符串需要創(chuàng)建時,如果常量池中存在相等的字符串就直接將引用指向已有的字符串常量,而不會創(chuàng)建新對象
  • new創(chuàng)建的對象存儲在堆內(nèi)存,不可能與常量區(qū)的對象具有相同地址
  • 直接用字面量初始化String要比用new 關(guān)鍵字創(chuàng)建String對象效率更高
public class Demo { public static void main(String[] args) throws Exception { String s = 'abc'; String s1 = 'abc'; String s2 = 'a' + 'bc'; final String str1 = 'a'; final String str2 = 'bc'; String s3 = str1 + str2; String s4 = new String('abc'); System.out.println(s == s1); System.out.println(s == s2); System.out.println(s == s3); System.out.println(s == s4); }} //結(jié)果:true true true false
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

為什么String不可變

final修飾變量,如果是基本類型那么內(nèi)容運(yùn)行期間不可變,如果是引用類型那么引用的對象(包括數(shù)組)運(yùn)行期地址不可變,但是對象(數(shù)組)的內(nèi)容是可以改變的

  • final只是保證value不會指向其他的數(shù)組,但不保證數(shù)組內(nèi)容不可修改
  • private屬性保證了不可以在類外訪問數(shù)組,也就不能改變其內(nèi)容
  • String內(nèi)部沒有改變value內(nèi)容的函數(shù),所以String就不可變了
  • String聲明為final杜絕了通過繼承的方法添加新的函數(shù)
  • 基于數(shù)組的構(gòu)造方法,會拷貝數(shù)組元素,從而避免了通過外部引用修改value的情況
  • 用String構(gòu)造其他可變對象時,涉及的數(shù)組只是返回的數(shù)組的拷貝而不是原數(shù)組,例如 new StringBuilder(str),會把str數(shù)組進(jìn)行拷貝后傳遞給StringBuilder而不是傳遞原數(shù)組

當(dāng)然只要類庫設(shè)計人愿意,只要增加一個類似的setCharAt(index)的接口,String就變成可變的了

private final char value[]; private int hash; // Default to 0 public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }
  • 1
  • 2
  • 3
  • 4
  • 5

通過反射改變String

  • final 只在編譯器有效,在運(yùn)行期間無效,因此可以通過反射改變value引用的對象
  • s與str始終具有相同的內(nèi)存地址,反射改變了s的內(nèi)容,并沒有新創(chuàng)建對象
  • s 與 s1對應(yīng)常量池中的兩個對象,所以即便通過反射修改了s的內(nèi)容,他們兩個的內(nèi)存地址還是不同的
public class Demo { public static void main(String[] args) throws Exception { String s = 'abc'; String str = s; String s1 = 'bbb'; System.out.println(str == s); Field f = s.getClass().getDeclaredField('value'); f.setAccessible(true); f.set(s, new char[]{'b', 'b', 'b'}); System.out.println(str + ' ' + s); System.out.println(s == str); System.out.println(s == s1); }} //結(jié)果:bbb bbb true false
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

String的HashCode

s的內(nèi)容改變了但是hashCode值并沒有改變,雖然s與s1的內(nèi)容是相同的但是他們hashCode值并不相同

  • Object的hashCode方法返回的是16進(jìn)制內(nèi)存地址,String類重寫了hashCode的,hashCode值的計算是基于字符串內(nèi)容的
  • String的hashCode值初始為0,由于String是不可變的,當(dāng)?shù)谝淮芜\(yùn)行完hashCode方法后String類對HashCode值進(jìn)行了緩存,下一次在調(diào)用時直接返回hash值
public class Demo { public static void main(String[] args) throws Exception { String s = 'abc'; String s1 = 'bbb'; System.out.println(s.hashCode()); Field f = s.getClass().getDeclaredField('value'); f.setAccessible(true); f.set(s, new char[]{'b', 'b', 'b'}); System.out.println(s + ' '+ s1); System.out.println(s.hashCode() +' ' +s1.hashCode()); }} //結(jié)果:96354 bbb bbb 96354 97314
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

String hashCode的源碼

public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length;="" i++)="" {="" h="">31 * h + val[i]; } hash = h; } return h; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

toString方法中的this

  • Java為String類重載了“+”操作符,String類與其他類對象進(jìn)行連接時會調(diào)用其他類的toString方法
  • 如果在其他類的toString方法中用“+”對this進(jìn)行連接就會出現(xiàn)無限遞歸調(diào)用而出現(xiàn)棧溢出錯誤
  • 解決方法將this換做super.this
public class Demo { @Override public String toString() { //會造成遞歸調(diào)用// return 'address'+super.toString(); return 'address'+super.toString(); } public static void main(String[] args) { System.out.println(new Demo()); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

CodePoints與CodeUnit

String的length表示的是代碼單元的個數(shù),而不是字符的個數(shù)

  • codePoints是代碼點(diǎn), 表示的是例如’A’, ‘王’ 這種字符,每種字符都有一個唯一的數(shù)字編號,這個數(shù)字編號就叫unicode code point。目前code point的數(shù)值范圍是0~0x10FFFF。
  • codeUnit是代碼單元, 它根據(jù)編碼不同而不同, 可以理解為是字符編碼的基本單元,java中的char是兩個字節(jié), 也就是16位的。這樣也反映了一個char只能表示從u+0000~u+FFFF范圍的unicode字符, 在這個范圍的字符也叫BMP(basic Multiligual Plane ), 超出這個范圍的叫增補(bǔ)字符,增補(bǔ)字符占用兩個代碼單元。
public class Demo { public static void main(String[] args) { String s = '\u1D56B'; System.out.println(s); System.out.println(s.length()); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

我們看看String是怎么處理增補(bǔ)字符的

  • 首先value字符數(shù)組的長度是根據(jù)代碼單元來定的,每出現(xiàn)一個Surrogate字符數(shù)組長度在count的基礎(chǔ)上加一
  • BMP字符直接存儲,增補(bǔ)字符的用兩個char分別存儲高位和低位
public String(int[] codePoints, int offset, int count) { if (offset <>0) { throw new StringIndexOutOfBoundsException(offset); } if (count <>0) { throw new StringIndexOutOfBoundsException(count); } // Note: offset or count might be near -1>>>1. if (offset > codePoints.length - count) { throw new StringIndexOutOfBoundsException(offset + count); } final int end = offset + count; // Pass 1: Compute precise size of char[] int n = count; for (int i = offset; i < end;="" i++)="" {="">int c = codePoints[i]; if (Character.isBmpCodePoint(c)) continue; else if (Character.isValidCodePoint(c)) n++; else throw new IllegalArgumentException(Integer.toString(c)); } // Pass 2: Allocate and fill in char[] final char[] v = new char[n]; for (int i = offset, j = 0; i < end;="" i++,="" j++)="" {="">int c = codePoints[i]; if (Character.isBmpCodePoint(c)) v[j] = (char)c; else Character.toSurrogates(c, v, j++); } this.value = v; } static void toSurrogates(int codePoint, char[] dst, int index) { // We write elements 'backwards' to guarantee all-or-nothing dst[index+1] = lowSurrogate(codePoint); dst[index] = highSurrogate(codePoint); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38

源碼解析

聲明

  • String類可序列化,可比較,實現(xiàn)CharSequence接口提供了對字符的基本操作
  • String內(nèi)部使用final字符數(shù)組進(jìn)行存儲,涉及value數(shù)組的操作都使用了拷貝數(shù)組元素的方法,保證了不能在外部修改字符數(shù)組
  • String重寫了Object的hashCode函數(shù)使hash值基于字符數(shù)組內(nèi)容,但是由于String緩存了hash值,所以即便通過反射改變了字符數(shù)組內(nèi)容,hashhashCode返回值不會自動更新
  • serialVersionUID 用來確定類的版本是否正確,如果不是同一個類會拋出InvalidCastException異常
public final class String implements java.io.Serializable, ComparableString>, CharSequence { private final char value[]; private static final long serialVersionUID = -6849794470754667710L; /** Cache the hash code for the string */ private int hash; // Default to 0 public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length;="" i++)="" {="" h="">31 * h + val[i]; } hash = h; } return h; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

構(gòu)造函數(shù)

  • String主要提供了通過String,StringBuilder,StringBuffer,char數(shù)組,int數(shù)組(CodePoint),byte數(shù)組(需要指定編碼)進(jìn)行初始化
  • 當(dāng)通過字符串初始化字符串時,并沒有執(zhí)行value數(shù)組拷貝,因為original的value數(shù)組是不可以在外部修改的,也就保證了新String對象的不可修改
  • 通過字符數(shù)組,StringBuffer,StringBuilder進(jìn)行初始化時,就要執(zhí)行value數(shù)組元素的拷貝,創(chuàng)建新數(shù)組,防止外部對value內(nèi)容的改變
  • 通過byte數(shù)組進(jìn)行初始化,需要指定編碼,或使用默認(rèn)編碼(ISO-8859-1),否則無法正確解釋字節(jié)內(nèi)容
  • 通過Unicode代碼點(diǎn)進(jìn)行的初始化,可能會包含非BMP字符(int值大于65535),這時候字符串的長度可能會長于int數(shù)組的長度,(見本文前面增補(bǔ)字符處理部分)
public String(String original) { this.value = original.value; this.hash = original.hash; } public String(StringBuffer buffer) { synchronized(buffer) { this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); } } public String(StringBuilder builder) { this.value = Arrays.copyOf(builder.getValue(), builder.length()); } public String(char value[]) { this.value = Arrays.copyOf(value, value.length); } public String(char value[], int offset, int count) { if (offset <>0) { throw new StringIndexOutOfBoundsException(offset); } if (count <>0) { throw new StringIndexOutOfBoundsException(count); } // 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 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); } public String(byte bytes[], int offset, int length) { checkBounds(bytes, offset, length); this.value = StringCoding.decode(bytes, offset, length); } static char[] decode(byte[] ba, int off, int len) { String csn = Charset.defaultCharset().name(); try { // use charset name decode() variant which provides caching. return decode(csn, ba, off, len); } catch (UnsupportedEncodingException x) { warnUnsupportedCharset(csn); } try { return decode('ISO-8859-1', ba, off, len); } catch (UnsupportedEncodingException x) { // If this code is hit during VM initialization, MessageUtils is // the only way we will be able to get any kind of error message. MessageUtils.err('ISO-8859-1 charset not available: ' + x.toString()); // If we can not find ISO-8859-1 (a required encoding) then things // are seriously wrong with the installation. System.exit(1); return null; } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

內(nèi)部構(gòu)造函數(shù)

使用外部數(shù)組來初始化String內(nèi)部數(shù)組只有保證傳入的數(shù)組不可能被改變才能保證String的不可變性,例如用String初始化String對象時

  • 這種方法使用共享value數(shù)組的方法避免了數(shù)組的拷貝,提高了效率
  • 上面分析指出如果直接使用外部傳入的數(shù)組不能保證String的不可變性,這個方法只在String的內(nèi)部使用,不能由外部調(diào)用
  • 添加share參數(shù),只是為了重載構(gòu)造函數(shù),share必須為true
  • 該函數(shù)只用在不能縮短String長度的函數(shù)中,如concat(str1,str2),如果用在縮短String長度的函數(shù)如subString中會造成內(nèi)存泄漏
String(char[] value, boolean share) { // assert share : 'unshared not supported'; this.value = value; } 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); } // 使用了Arrays.copyof方法來構(gòu)造新的數(shù)組,拷貝元素,而不是共用數(shù)組 public String substring(int beginIndex) { if (beginIndex <>0) { throw new StringIndexOutOfBoundsException(beginIndex); } int subLen = value.length - beginIndex; if (subLen <>0) { throw new StringIndexOutOfBoundsException(subLen); } return (beginIndex == 0) ? this : new String(value, beginIndex, subLen); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

如果String(value,share)可以在外部使用,就可以改變字符串內(nèi)容

public class Demo { public static void main(String[] args) { char[] arr = new char[] {'h', 'e', 'l', 'l', 'o', ' ', 'w', 'o', 'r', 'l', 'd'}; String s = new String(arr,true); arr[0] = 'a'; System.out.println(s); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

aLongString 已經(jīng)不用了,但是由于其與aPart共享value數(shù)組,所以不能被回收,造成內(nèi)存泄漏

public String subTest(){ String aLongString = '...a very long string...'; String aPart = aLongString.substring(20, 40); return aPart; }
  • 1
  • 2
  • 3
  • 4
  • 5

主要方法

其他主要方法

length() 返回字符串長度isEmpty() 返回字符串是否為空charAt(int index) 返回字符串中第(index+1)個字符char[] toCharArray() 轉(zhuǎn)化成字符數(shù)組trim() 去掉兩端空格toUpperCase() 轉(zhuǎn)化為大寫toLowerCase() 轉(zhuǎn)化為小寫String concat(String str) //拼接字符串String replace(char oldChar, char newChar) //將字符串中的oldChar字符換成newChar字符//以上兩個方法都使用了String(char[] value, boolean share);boolean matches(String regex) //判斷字符串是否匹配給定的regex正則表達(dá)式boolean contains(CharSequence s) //判斷字符串是否包含字符序列sString[] split(String regex, int limit) 按照字符regex將字符串分成limit份。String[] split(String regex)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

重載的valueOf方法

可以看到主要是調(diào)用構(gòu)造函數(shù)或者是調(diào)用對應(yīng)類型的toString完成到字符串的轉(zhuǎn)換

public static String valueOf(boolean b) { return b ? 'true' : 'false'; } public static String valueOf(char c) { char data[] = {c}; return new String(data, true); } public static String valueOf(int i) { return Integer.toString(i); } public static String valueOf(long l) { return Long.toString(l); } public static String valueOf(float f) { return Float.toString(f); } public static String valueOf(double d) { return Double.toString(d); } public static String valueOf(char data[], int offset, int count) { return new String(data, offset, count); } public static String copyValueOf(char data[], int offset, int count) { // All public String constructors now copy the data. return new String(data, offset, count); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

字符串查找算法 indexOf

可以看到String的字符串匹配算法使用的是樸素的匹配算法,即前向匹配,當(dāng)遇到不匹配字符時,主串從下一個字符開始,字串從開始位置開始
其他相關(guān)字符串匹配算法

static int indexOf(char[] source, int sourceOffset, int sourceCount, char[] target, int targetOffset, int targetCount, int fromIndex) { if (fromIndex >= sourceCount) { return (targetCount == 0 ? sourceCount : -1); } if (fromIndex <>0) { fromIndex = 0; } if (targetCount == 0) { return fromIndex; } char first = target[targetOffset]; int max = sourceOffset + (sourceCount - targetCount); for (int i = sourceOffset + fromIndex; i <= max;="" i++)="" {="">/* Look for first character. */ if (source[i] != first) { while (++i <= max="" &&="" source[i]="" !="first);" }="">/* Found first character, now look at the rest of v2 */ if (i <= max)="" {="">int j = i + 1; int end = j + targetCount - 1; for (int k = targetOffset + 1; j < end="" &&="" source[j]="=" target[k];="" j++,="" k++);="">if (j == end) { /* Found whole string. */ return i - sourceOffset; } } } return -1; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33

編碼問題 getBytes

  • 字符串最終都是使用機(jī)器碼以字節(jié)存儲的,當(dāng)我們將字符串轉(zhuǎn)換為字節(jié)的時候也需要給定編碼,同一個字符不同的編碼就對應(yīng)不同的字節(jié)
  • 如不指定編碼,就會使用默認(rèn)的編碼ISO-8859-1進(jìn)行編碼
  • 編碼時為了避免平臺編碼的干擾,應(yīng)當(dāng)指定確定的編碼
String s = '你好,世界!'; byte[] bytes = s.getBytes('utf-8'); public byte[] getBytes(String charsetName) throws UnsupportedEncodingException { if (charsetName == null) throw new NullPointerException(); return StringCoding.encode(charsetName, value, 0, value.length); } static byte[] encode(String charsetName, char[] ca, int off, int len) throws UnsupportedEncodingException { StringEncoder se = deref(encoder); String csn = (charsetName == null) ? 'ISO-8859-1' : charsetName; if ((se == null) || !(csn.equals(se.requestedCharsetName()) || csn.equals(se.charsetName()))) { se = null; try { Charset cs = lookupCharset(csn); if (cs != null) se = new StringEncoder(cs, csn); } catch (IllegalCharsetNameException x) {} if (se == null) throw new UnsupportedEncodingException (csn); set(encoder, se); } return se.encode(ca, off, len); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

比較方法

  • 所有比較方法都是比較對應(yīng)的字符數(shù)組的內(nèi)容,后兩個比較方法用來進(jìn)行區(qū)段比較
  • 在進(jìn)行數(shù)組比較時,如果可以通過長度進(jìn)行初步判斷,一般可以提高效率
boolean equals(Object anObject); boolean contentEquals(StringBuffer sb); boolean contentEquals(CharSequence cs); boolean equalsIgnoreCase(String anotherString); int compareTo(String anotherString); int compareToIgnoreCase(String str); boolean regionMatches(int toffset, String other, int ooffset,int len) //局部匹配 boolean regionMatches(boolean ignoreCase, int toffset,String other, int ooffset, int len) //局部匹配 public boolean equals(Object anObject) { if (this == anObject) { return true; } if (anObject instanceof String) { String anotherString = (String) anObject; int n = value.length; if (n == anotherString.value.length) { char v1[] = value; char v2[] = anotherString.value; int i = 0; while (n-- != 0) { if (v1[i] != v2[i]) return false; i++; } return true; } } return false; }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30

替換函數(shù) replace

  • 單字符替換會替換所有特定字符的出現(xiàn)
  • replace為普通(literal)替換,不用正則表達(dá)式
  • replaceFirst與replaceAll都使用了正則表達(dá)式
public String replace(CharSequence target, CharSequence replacement) { return Pattern.compile(target.toString(), Pattern.LITERAL).matcher( this).replaceAll(Matcher.quoteReplacement(replacement.toString())); } public String replaceFirst(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceFirst(replacement); } public String replaceAll(String regex, String replacement) { return Pattern.compile(regex).matcher(this).replaceAll(replacement); } 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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

常量池相關(guān)方法

  • 每當(dāng)定義一個字符串字面量,字面量進(jìn)行字符串連接,或者final的String字面量初始化的變量的連接的變量時都會檢查常量池中是否有對應(yīng)的字符串,如果有就不創(chuàng)建新的字符串,而是返回指向常量池對應(yīng)字符串的引用
  • 所有通過new String(str)方式創(chuàng)建的對象都會存在與堆區(qū),而非常量區(qū)
  • 普通變量的連接,由于不能在編譯期確定下來,所以不會存儲在常量區(qū)
public native String intern();
  • 1

運(yùn)算符的重載

  • String對“+”運(yùn)算符進(jìn)行了重載,通過反編譯我們看到重載是通過StringBuilder的append方法,及String的valueOf方法實現(xiàn)的
  • int值轉(zhuǎn)String過程中(”“+i)這種方法實際為(new StringBuilder()).append(i).toString();,而另外兩種都是調(diào)用Integer的靜態(tài)方法Integer.toString完成
// int轉(zhuǎn)String的方法比較public class Demo { public static void main(String[] args) throws Exception { int i = 5; String i1 = '' + i; String i2 = String.valueOf(i); String i3 = Integer.toString(i); }} // 原始代碼public class Demo { public static void main(String[] args) throws Exception { String string='hollis'; String string2 = string + 'chuang'; }} //反編譯代碼public class Demo { public static void main(String[] args) throws Exception { String string = 'hollis'; String string2 = (new StringBuilder(String.valueOf(string))).append('chuang').toString(); }}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
408,劍指 Offer-替換空格
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服