一.String
1.1string源碼中,幾個變量 :
String類有final修飾,所以String類不能被繼承
@Stable
private final byte[] value; final 是不可變的;因爲private是私有的,並且沒有提供修改value數組的方法,所以一旦確定值是不可變的;
構造函數:
public String() {
this.value = "".value;
this.coder = "".coder;
}
public String(String original) {
this.value = original.value;
this.coder = original.coder;
this.hash = original.hash;
}
1.2 方法:
1.2.1 equals 方法
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String aString = (String)anObject;
if (coder() == aString.coder()) {
return isLatin1() ? StringLatin1.equals(value, aString.value)
: StringUTF16.equals(value, aString.value);
}
}
return false;
}
latin1碼下的比較
public static boolean equals(byte[] value, byte[] other) {
if (value.length == other.length) {
for (int i = 0; i < value.length; i++) {
if (value[i] != other[i]) {
return false;
}
}
2.StringBuffer 繼承自abstractStringBuffer
變量:
byte[] value;
不是final的可以改變,並且權限是默認的;
繼承自abstractStringBuilder
append方法:
擴容的新容量爲當前value的容量2倍加2,如果擴容後的容量還是比需要的最小容量小,則直接擴容爲需要的最小容量,再將當前value內容複製給一個新的長度爲newCapacity的字符數組,再將value指向這個擴容後的新數組。即擴容是通過開闢新數組完成的,返回的也是新創建的新數組。
先擴容,將原先的數組複製到新數組中;
*/
public AbstractStringBuilder append(String str) {
if (str == null) {
return appendNull();
}
int len = str.length();
ensureCapacityInternal(count + len);
putStringAt(count, str);
count += len;
return this;
}
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
if (minimumCapacity - oldCapacity > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity) << coder);
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int oldCapacity = value.length >> coder;
int newCapacity = (oldCapacity << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
int SAFE_BOUND = MAX_ARRAY_SIZE >> coder;
return (newCapacity <= 0 || SAFE_BOUND - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
3.String與StringBuffer與StringBuilder三者介紹和三者的區別:
string 是不可變的,每次對string的操作其實是生成一個新的string對象;
tringBuffer與StringBuilder,是對自己本身操作的,並不產生新對象;
因爲在源碼中,string的值存放在value的char[] 數組中,這個value變量值final的並且是private,並且源碼中並沒有可以改變value數組的方法,同時stringbuffer的value數組權限是默認的且非final的;
StringBuilder是線程非安全的,stringbuffer是線程安全方法加鎖的;
二.list
1.ArrayList
底層由數組實現,
最主要的方法:
add(): 初始 默認是10; 先查詢是否進行擴容,如果擴容Array.copyof()方法,擴到1.5倍,;
remove() 其實底層用的是system.arraycopy;
public int size() { return size; }
返回的size是變量,是list的長度,而不是數組的長度;
2. ArrayList 的安全問題
ArrayList 採用fail-fast 機制,是java集合的一中失敗檢測機制,在迭代過程中報錯;
具體場景是:
List<String> list = new ArrayList<>();
for (int i = 0 ; i < 10 ; i++ ) {
list.add(i + "");
}
Iterator<String> iterator = list.iterator();
int i = 0 ;
while(iterator.hasNext()) {
if (i == 3) {
list.remove(3); //改成iterator.remove(3)方法代替就可以解決
}
System.out.println(iterator.next());
i ++;
}
//這個時候就會報錯,因爲當ArraList在添加或者刪除操作時,會有個專門的記錄修改次數的變量+1,而在執行iterator.next()操作時候,會 進行一個判讀 expectedModCount和門的記錄修改次數的變量的判斷,這個時候就會報錯;
解決方法 : list.remove(3); //改成iterator.remove(3)方法代替就可以解決;
2.linkedList
雙向鏈表
變量:
Node : first last;
方法 :
get(int index) //獲取指定位置的節點:
會把index 與size/2比,小於,從頭開始遍歷查找,大於從尾部查找開始;
也同時實現了普通隊列和棧的功能:
//出隊(從前端),如果不存在會返回null,存在的話會返回值並移除這個元素(節點)
public E poll() {
final Node<E> f = first;
return (f == null) ? null : unlinkFirst(f);
}
//出隊(從前端),如果不存在會拋出異常而不是返回null,存在的話會返回值並移除這個元素(節點)
public E remove() {
return removeFirst();
}
構造函數:
其中有個構造函數
public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
addAll方法把c轉換成數組,然後遍歷數組一個個添加,
三. map
1.hashMap
hashMap 是數組+鏈表的形式,根據key的hashcode 來確定放到哪個桶,當兩個key的hashcode相同時候,需要放在一個桶中,這個時候就用鏈表,如果鏈表長度超過(默認),就轉成紅黑樹;
如果數組越長 那麼hash衝突的概率就越小,而查找效率越快,但空間的佔用就越多,所以這個時候,出現了擴容機制;
擴容機制是 根據默認負載因子0.75,threshold=負載因子 * length; //判斷是否需要擴容,每次擴容*2;HashMap是先插入數據再進行擴容的,但是如果是剛剛初始化容器的時候是先擴容再插入數據。
擴容之後的hash計算 :只需要看看原來的hash值新增的那個bit是1還是0就好了,是0的話索引沒變,是1的話索引變成“原索引+oldCap”,
put()方法
檢測table[]是否爲空,
檢測table[i]是否爲插入過,選擇直接插入,或者遍歷
然後看是否鏈表超過8,編程紅黑樹;
如果key相同覆蓋,如果不是插入,
2.hashtable
hashtable 相對來說是線程安全的,加了鎖; 初始容量11 每次擴容2n+1;ashMap的迭代器(Iterator)是fail-fast迭代器;
Map m = Collections.synchronizeMap(hashMap);(讓hashmap變線程安全);
3.