Java String原始碼解析
String類概要
- 所有的字串字面量都屬於String類,String物件建立後不可改變,因此可以快取共享,StringBuilder,StringBuffer是可變的實現
- String類提供了操作字元序列中單個字元的方法,比如有比較字串,搜尋字串等
- Java語言提供了對字串連線運算子的特別支援(+),該符號也可用於將其他型別轉換成字串。
- 字串的連線實際上是通過StringBuffer或者StringBuilder的append()方法來實現的
- 一般情況下,傳遞一個空引數在這類建構函式或方法會導致NullPointerException異常被丟擲。
- String表示一個字串通過UTF-16(unicode)格式,補充字元通過代理對錶示。索引值參考字元編碼單元,所以補充字元在String中佔兩個位置。
String是不可變的
- String是常量,一旦被建立就不可被改變,因此可以用來共享
從String的怪異現象講起
String是否相等
==判斷的是物件的記憶體起始地址是否相同,equals判斷自定義的語義是否相同
- JVM為了提高記憶體效率,將所有不可變的字串快取在常量池中,當有新的不可變的字串需要建立時,如果常量池中存在相等的字串就直接將引用指向已有的字串常量,而不會建立新物件
- new建立的物件儲存在堆記憶體,不可能與常量區的物件具有相同地址
- 直接用字面量初始化String要比用new 關鍵字建立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);
}
} //結果:true true true false
為什麼String不可變
final修飾變數,如果是基本型別那麼內容執行期間不可變,如果是引用型別那麼引用的物件(包括陣列)執行期地址不可變,但是物件(陣列)的內容是可以改變的
- final只是保證value不會指向其他的陣列,但不保證陣列內容不可修改
- private屬性保證了不可以在類外訪問陣列,也就不能改變其內容
- String內部沒有改變value內容的函式,所以String就不可變了
- String宣告為final杜絕了通過繼承的方法新增新的函式
- 基於陣列的構造方法,會拷貝陣列元素,從而避免了通過外部引用修改value的情況
- 用String構造其他可變物件時,涉及的陣列只是返回的陣列的拷貝而不是原陣列,例如 new StringBuilder(str),會把str陣列進行拷貝後傳遞給StringBuilder而不是傳遞原陣列
當然只要類庫設計人願意,只要增加一個類似的setCharAt(index)的介面,String就變成可變的了
private final char value[];
private int hash; // Default to 0
public String(char value[]) {
this.value = Arrays.copyOf(value, value.length);
}
通過反射改變String
- final 只在編譯器有效,在執行期間無效,因此可以通過反射改變value引用的物件
- s與str始終具有相同的記憶體地址,反射改變了s的內容,並沒有新建立物件
- s 與 s1對應常量池中的兩個物件,所以即便通過反射修改了s的內容,他們兩個的記憶體地址還是不同的
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);
}
} //結果:bbb bbb true false
String的HashCode
s的內容改變了但是hashCode值並沒有改變,雖然s與s1的內容是相同的但是他們hashCode值並不相同
- Object的hashCode方法返回的是16進位制記憶體地址,String類重寫了hashCode的,hashCode值的計算是基於字串內容的
- String的hashCode值初始為0,由於String是不可變的,當第一次執行完hashCode方法後String類對HashCode值進行了快取,下一次在呼叫時直接返回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());
}
} //結果:96354 bbb bbb 96354 97314
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;
}
toString方法中的this
- Java為String類過載了“+”操作符,String類與其他類物件進行連線時會呼叫其他類的toString方法
- 如果在其他類的toString方法中用“+”對this進行連線就會出現無限遞迴呼叫而出現棧溢位錯誤
- 解決方法將this換做super.this
public class Demo {
@Override
public String toString() {
//會造成遞迴呼叫
// return "address"+super.toString();
return "address"+super.toString();
}
public static void main(String[] args) {
System.out.println(new Demo());
}
}
CodePoints與CodeUnit
String的length表示的是程式碼單元的個數,而不是字元的個數
- codePoints是程式碼點, 表示的是例如’A’, ‘王’ 這種字元,每種字元都有一個唯一的數字編號,這個數字編號就叫unicode code point。目前code point的數值範圍是0~0x10FFFF。
- codeUnit是程式碼單元, 它根據編碼不同而不同, 可以理解為是字元編碼的基本單元,java中的char是兩個位元組, 也就是16位的。這樣也反映了一個char只能表示從u+0000~u+FFFF範圍的unicode字元, 在這個範圍的字元也叫BMP(basic Multiligual Plane ), 超出這個範圍的叫增補字元,增補字元佔用兩個程式碼單元。
public class Demo {
public static void main(String[] args) {
String s = "\u1D56B";
System.out.println(s);
System.out.println(s.length());
}
}
我們看看String是怎麼處理增補字元的
- 首先value字元陣列的長度是根據程式碼單元來定的,每出現一個Surrogate字元陣列長度在count的基礎上加一
- BMP字元直接儲存,增補字元的用兩個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);
}
原始碼解析
宣告
- String類可序列化,可比較,實現CharSequence介面提供了對字元的基本操作
- String內部使用final字元陣列進行儲存,涉及value陣列的操作都使用了拷貝陣列元素的方法,保證了不能在外部修改字元陣列
- String重寫了Object的hashCode函式使hash值基於字元陣列內容,但是由於String快取了hash值,所以即便通過反射改變了字元陣列內容,hashhashCode返回值不會自動更新
- serialVersionUID 用來確定類的版本是否正確,如果不是同一個類會丟擲InvalidCastException異常
public final class String
implements java.io.Serializable, Comparable<String>, 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;
}
建構函式
- String主要提供了通過String,StringBuilder,StringBuffer,char陣列,int陣列(CodePoint),byte陣列(需要指定編碼)進行初始化
- 當通過字串初始化字串時,並沒有執行value陣列拷貝,因為original的value陣列是不可以在外部修改的,也就保證了新String物件的不可修改
- 通過字元陣列,StringBuffer,StringBuilder進行初始化時,就要執行value陣列元素的拷貝,建立新陣列,防止外部對value內容的改變
- 通過byte陣列進行初始化,需要指定編碼,或使用預設編碼(ISO-8859-1),否則無法正確解釋位元組內容
- 通過Unicode程式碼點進行的初始化,可能會包含非BMP字元(int值大於65535),這時候字串的長度可能會長於int陣列的長度,(見本文前面增補字元處理部分)
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;
}
}
內部建構函式
使用外部陣列來初始化String內部陣列只有保證傳入的陣列不可能被改變才能保證String的不可變性,例如用String初始化String物件時
- 這種方法使用共享value陣列的方法避免了陣列的拷貝,提高了效率
- 上面分析指出如果直接使用外部傳入的陣列不能保證String的不可變性,這個方法只在String的內部使用,不能由外部呼叫
- 新增share引數,只是為了過載建構函式,share必須為true
- 該函式只用在不能縮短String長度的函式中,如concat(str1,str2),如果用在縮短String長度的函式如subString中會造成記憶體洩漏
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方法來構造新的陣列,拷貝元素,而不是共用陣列
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);
}
如果String(value,share)可以在外部使用,就可以改變字串內容
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);
}
}
aLongString 已經不用了,但是由於其與aPart共享value陣列,所以不能被回收,造成記憶體洩漏
public String subTest(){
String aLongString = "...a very long string...";
String aPart = aLongString.substring(20, 40);
return aPart;
}
主要方法
其他主要方法
length() 返回字串長度
isEmpty() 返回字串是否為空
charAt(int index) 返回字串中第(index+1)個字元
char[] toCharArray() 轉化成字元陣列
trim() 去掉兩端空格
toUpperCase() 轉化為大寫
toLowerCase() 轉化為小寫
String concat(String str) //拼接字串
String replace(char oldChar, char newChar) //將字串中的oldChar字元換成newChar字元
//以上兩個方法都使用了String(char[] value, boolean share);
boolean matches(String regex) //判斷字串是否匹配給定的regex正則表示式
boolean contains(CharSequence s) //判斷字串是否包含字元序列s
String[] split(String regex, int limit) 按照字元regex將字串分成limit份。
String[] split(String regex)
過載的valueOf方法
可以看到主要是呼叫建構函式或者是呼叫對應型別的toString完成到字串的轉換
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);
}
字串查詢演算法 indexOf
可以看到String的字串匹配演算法使用的是樸素的匹配演算法,即前向匹配,當遇到不匹配字元時,主串從下一個字元開始,字串從開始位置開始
其他相關字串匹配演算法
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;
}
編碼問題 getBytes
- 字串最終都是使用機器碼以位元組儲存的,當我們將字串轉換為位元組的時候也需要給定編碼,同一個字元不同的編碼就對應不同的位元組
- 如不指定編碼,就會使用預設的編碼ISO-8859-1進行編碼
- 編碼時為了避免平臺編碼的干擾,應當指定確定的編碼
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);
}
比較方法
- 所有比較方法都是比較對應的字元陣列的內容,後兩個比較方法用來進行區段比較
- 在進行陣列比較時,如果可以通過長度進行初步判斷,一般可以提高效率
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;
}
替換函式 replace
- 單字元替換會替換所有特定字元的出現
- replace為普通(literal)替換,不用正則表示式
- replaceFirst與replaceAll都使用了正則表示式
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;
}
常量池相關方法
- 每當定義一個字串字面量,字面量進行字串連線,或者final的String字面量初始化的變數的連線的變數時都會檢查常量池中是否有對應的字串,如果有就不建立新的字串,而是返回指向常量池對應字串的引用
- 所有通過new String(str)方式建立的物件都會存在與堆區,而非常量區
- 普通變數的連線,由於不能在編譯期確定下來,所以不會儲存在常量區
public native String intern();
運算子的過載
- String對“+”運算子進行了過載,通過反編譯我們看到過載是通過StringBuilder的append方法,及String的valueOf方法實現的
- int值轉String過程中(”“+i)這種方法實際為(new StringBuilder()).append(i).toString();,而另外兩種都是呼叫Integer的靜態方法Integer.toString完成
// int轉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();
}
}
相關推薦
Java String原始碼解析
String類概要 所有的字串字面量都屬於String類,String物件建立後不可改變,因此可以快取共享,StringBuilder,StringBuffer是可變的實現 String類提供了操作字元序列中單個字元的方法,比如有比較字串,搜尋字串等 Jav
Java——ArrayList原始碼解析
以下針對JDK 1.8版本中的ArrayList進行分析。 概述 ArrayList基於List介面實現的大小可變的陣列。其實現了所有可選的List操作,並且元素允許為任意型別,包括null元素。除了實現List介面,此類還提供了操作內部用於儲存列表陣列大小
Java——HashMap原始碼解析
以下針對JDK 1.8版本中的HashMap進行分析。 概述 雜湊表基於Map介面的實現。此實現提供了所有可選的對映操作,並且允許鍵為null,值也為null。HashMap 除了不支援同步操作以及支援null的鍵值外,其功能大致等同於 Hashtable。
java集合原始碼解析(三)--List
今天給大家帶來有序集合的介面List,我想也應該是大家在工作中用的比較多的 先來看看介面的定義: public interface List<E> extends Collection<E>可以看出介面List直接繼承於介面Collection,並且一樣使用了
java集合原始碼解析(二)--AbstractCollection
今天帶來的是java單列頂層介面的第一個輕量級實現:AbstractCollection 我們直接進入正題,先來看看它的宣告: package java.util; //可以從名字上同樣看到 AbstractCollection 是一個抽象類,所以並不能例項化, //這個類只是作
Java ThreadLocal原始碼解析: ThreadLocalMap
ThreadLocalMap在比其中Thread和ThreadLocal部分要複雜很多,是ThreadLocal底層儲存和核心資料結構。從整體上將,ThreadLocalMap底層是Entry陣列,key值為ThreadLocal的hash code, 採用線性探測法解決雜湊衝突。 以下
Java ThreadLocal原始碼解析: Thread和ThreadLocal
之前對TreadLocal有所理解,對原理也有所瞭解,但一直不深入,重新整理,希望藉以加深理解和印象。 在Jdk1.8中,ThreadLocal相關程式碼主要分為三部分: Thread,其中Thread中儲存對ThreadLocal.ThreadLocalMap的引用,作為T
String原始碼解析(JDK1.8)
1、string類的定義 public final class String implements java.io.Serializable, Comparable<String>, CharSequence {} java.io.Serializa
Java 集合原始碼解析(1):Iterator
Java 提供的 集合類都在 Java.utils 包下,其中包含了很多 List, Set, Map, Queue… 它們的關係如下面這張類圖所示: 可以看到,Java 集合主要分為兩類:Collection 和 Map. 而 Collection 又繼承了 Iter
Java JDK原始碼解析之:native方法
初次看見native關鍵字是自己在看Scanner類原始碼中傳遞System.in引數實現列印,之後轉到System觀看原始碼時看見native關鍵字,關於native關鍵字筆者表示,是Java與C語言的通訊介面,因為Java語言沒有操作底層的條件,所以Java
Java集合原始碼解析:TreeMap
本文概要 二叉查詢樹的用處 二叉查詢樹,以及二叉樹帶來的問題 平衡二叉樹的好處 紅黑樹的定義以及構造 紅黑樹在TreeMap的運用 二叉樹的好處 可能許多人會有疑問,為什麼要使用二叉樹,有那麼多的資料結構,比如陣列、連結串列等 簡單看下陣列和連結串列的優缺點
Java集合原始碼解析:HashMap
本文概要 HashMap概述 HashMap資料結構 HashMap的原始碼解析 HashMap概述 在官方文件中是這樣描述的: Hash table based implementation of the Map interface. This imple
java 列舉原始碼解析
應用場景 列舉通常用來列舉一個型別的有限例項集合,我們可以使用常量集來實現,jdk1.5添加了列舉(enum)支援,解決了常量集的一些缺陷 常量集中的變數不會必然在指定的範圍內 常量能夠提供的功能很少,難於使用 常量意義不明確,沒有名字 修改或增加列舉值後
String原始碼解析二
一.intern方法 1.定義 /** * Returns a canonical representation for the string object. * <p> * A pool of strings, initially empty, is mainta
JAVA集合原始碼解析 Hashtable探索(基於JDK1.8)
JDK1.8Hashtable探索 本文的討論分析是基於JDK1.8進行的 依舊是採用前幾篇文章的大綱來進行介紹 1.簡介 Hashtable 採用陣列+單鏈表來實現的,Hashtable 實現了一個雜湊表,它將鍵對映到值。任何非 nu
java String原始碼淺出
1、public char charAt(int index) 返回指定索引處的 char 值。 原始碼: =====================String.class============================
java集合原始碼解析:collection
JAVA集合的框架圖: 從圖中可以看出集合分為collection 和 map 兩大類, 其中collection內部主要以陣列或者連結串列的形式存放一系列集合物件,map則是以系列鍵值對的集合 collection主要包含list 和 set 兩個部分,是list和
Java ArrayBlockingQueue原始碼解析
ArrayBlockingQueue是Java併發框架中阻塞佇列的最基本的實現,分析這個類就可以知道併發框架中是如何實現阻塞的。 筆者工作了一兩年之後,還不知道阻塞是如何實現的,當然有一個原因是前期學習的東西比較雜,前後端的東西的懂一點,但是瞭解的不夠深刻,我覺得這是程式設計學習的禁忌,不管是前端還是後
Java String 原始碼淺析
String表示字串,Java中所有字串的字面值都是String類的例項,例如“ABC”。字串是常量,在定義之後不能被改變,字串緩衝區支援可變的字串。因為 String 物件是不可變的,所以可以共享它們。例如: String str = "abc"; 相當於 char
Java Thread 原始碼解析
Thread 原始碼解析 執行緒的方法大部分都是使用Native使用,不允許應用層修改,是CPU排程的最基本單元。執行緒的資源開銷相對於程序的開銷是相對較少的,所以我們一般建立執行緒執行,而不是程序執行。 Thread 構造方法 /** * In