系列文章請檢視:
List,Set,Map三者的區別及總結
-
List:對付順序的好幫手
List介面儲存一組不唯一(可以有多個元素引用相同的物件),有序的物件
-
Set:注重獨一無二的性質
不允許重複的集合。不會有多個元素引用相同的物件。
-
Map:用Key來搜尋的專家
使用鍵值對儲存。Map會維護與Key有關聯的值。兩個Key可以引用相同的物件,但Key不能重複,典型的Key是String型別,但也可以是任何物件。
Arraylist 與 LinkedList 區別
Arraylist底層使用的是陣列(存讀資料效率高,插入刪除特定位置效率低),LinkedList底層使用的是雙向迴圈連結串列資料結構(插入,刪除效率特別高)。學過資料結構這門課後我們就知道採用連結串列儲存,插入,刪除元素時間複雜度不受元素位置的影響,都是近似O(1)而陣列為近似O(n),因此當資料特別多,而且經常需要插入刪除元素時建議選用LinkedList.一般程式只用Arraylist就夠用了,因為一般資料量都不會蠻大,Arraylist是使用最多的集合類。
ArrayList 與 Vector 區別(為什麼要用Arraylist取代Vector呢?)
Vector類的所有方法都是同步的。可以由兩個執行緒安全地訪問一個Vector物件、但是一個執行緒訪問Vector ,程式碼要在同步操作上耗費大量的時間。Arraylist不是同步的,所以在不需要同步時建議使用Arraylist。
HashMap 和 Hashtable 的區別
-
HashMap是非執行緒安全的,HashTable是執行緒安全的;HashTable內部的方法基本都經過synchronized修飾。
-
因為執行緒安全的問題,HashMap要比HashTable效率高一點,HashTable基本被淘汰。
-
HashMap允許有null值的存在,而在HashTable中put進的鍵值只要有一個null,直接丟擲NullPointerException。
Hashtable和HashMap有幾個主要的不同:執行緒安全以及速度。僅在你需要完全的執行緒安全的時候使用Hashtable,而如果你使用Java5或以上的話,請使用ConcurrentHashMap吧
HashSet 和 HashMap 區別
HashMap 和 ConcurrentHashMap 的區別
- ConcurrentHashMap對整個桶陣列進行了分割分段(Segment),然後在每一個分段上都用lock鎖進行保護,相對於HashTable的synchronized鎖的粒度更精細了一些,併發效能更好,而HashMap沒有鎖機制,不是執行緒安全的。(JDK1.8之後ConcurrentHashMap啟用了一種全新的方式實現,利用CAS演算法。)
- HashMap的鍵值對允許有null,但是ConCurrentHashMap都不允許。
HashSet如何檢查重複
當你把物件加入HashSet時,HashSet會先計算物件的hashcode值來判斷物件加入的位置,同時也會與其他加入的物件的hashcode值作比較,如果沒有相符的hashcode,HashSet會假設物件沒有重複出現。但是如果發現有相同hashcode值的物件,這時會呼叫equals()方法來檢查hashcode相等的物件是否真的相同。如果兩者相同,HashSet就不會讓加入操作成功。(摘自我的Java啟蒙書《Head fist java》第二版)
hashCode()與equals()的相關規定:
- 如果兩個物件相等,則hashcode一定也是相同的
- 兩個物件相等,對兩個equals方法返回true
- 兩個物件有相同的hashcode值,它們也不一定是相等的
- 綜上,equals方法被覆蓋過,則hashCode方法也必須被覆蓋
- hashCode()的預設行為是對堆上的物件產生獨特值。如果沒有重寫hashCode(),則該class的兩個物件無論如何都不會相等(即使這兩個物件指向相同的資料)。
==與equals的區別
- ==是判斷兩個變數或例項是不是指向同一個記憶體空間 equals是判斷兩個變數或例項所指向的記憶體空間的值是不是相同
- ==是指對記憶體地址進行比較 equals()是對字串的內容進行比較3.==指引用是否相同 equals()指的是值是否相同
comparable 和 comparator的區別?
- comparable介面實際上是出自java.lang包 它有一個 compareTo(Object obj)方法用來排序
- comparator介面實際上是出自 java.util 包它有一個compare(Object obj1, Object obj2)方法用來排序
一般我們需要對一個集合使用自定義排序時,我們就要重寫compareTo方法或compare方法,當我們需要對某一個集合實現兩種排序方式,比如一個song物件中的歌名和歌手名分別採用一種排序方法的話,我們可以重寫compareTo方法和使用自制的Comparator方法或者以兩個Comparator來實現歌名排序和歌星名排序,第二種代表我們只能使用兩個引數版的Collections.sort().
Comparator定製排序
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/**
* TODO Collections類方法測試之排序
* @author 寇爽
* @date 2017年11月20日
* @version 1.8
*/
public class CollectionsSort {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<Integer>();
arrayList.add(-1);
arrayList.add(3);
arrayList.add(3);
arrayList.add(-5);
arrayList.add(7);
arrayList.add(4);
arrayList.add(-9);
arrayList.add(-7);
System.out.println("原始陣列:");
System.out.println(arrayList);
// void reverse(List list):反轉
Collections.reverse(arrayList);
System.out.println("Collections.reverse(arrayList):");
System.out.println(arrayList);
/*
* void rotate(List list, int distance),旋轉。
* 當distance為正數時,將list後distance個元素整體移到前面。當distance為負數時,將
* list的前distance個元素整體移到後面。
Collections.rotate(arrayList, 4);
System.out.println("Collections.rotate(arrayList, 4):");
System.out.println(arrayList);*/
// void sort(List list),按自然排序的升序排序
Collections.sort(arrayList);
System.out.println("Collections.sort(arrayList):");
System.out.println(arrayList);
// void shuffle(List list),隨機排序
Collections.shuffle(arrayList);
System.out.println("Collections.shuffle(arrayList):");
System.out.println(arrayList);
// 定製排序的用法
Collections.sort(arrayList, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o2.compareTo(o1);
}
});
System.out.println("定製排序後:");
System.out.println(arrayList);
}
}
複製程式碼
重寫compareTo方法實現按年齡來排序
package map;
import java.util.Set;
import java.util.TreeMap;
public class TreeMap2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
TreeMap<Person, String> pdata = new TreeMap<Person, String>();
pdata.put(new Person("張三", 30), "zhangsan");
pdata.put(new Person("李四", 20), "lisi");
pdata.put(new Person("王五", 10), "wangwu");
pdata.put(new Person("小紅", 5), "xiaohong");
// 得到key的值的同時得到key所對應的值
Set<Person> keys = pdata.keySet();
for (Person key : keys) {
System.out.println(key.getAge() + "-" + key.getName());
}
}
}
// person物件沒有實現Comparable介面,所以必須實現,這樣才不會出錯,才可以使treemap中的資料按順序排列
// 前面一個例子的String類已經預設實現了Comparable介面,詳細可以檢視String類的API文件,另外其他
// 像Integer類等都已經實現了Comparable介面,所以不需要另外實現了
class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
/**
* TODO重寫compareTo方法實現按年齡來排序
*/
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
if (this.age > o.getAge()) {
return 1;
} else if (this.age < o.getAge()) {
return -1;
}
return age;
}
}
複製程式碼
如何對Object的list排序?
- 對objects陣列進行排序,我們可以用Arrays.sort()方法
- 對objects的集合進行排序,需要使用Collections.sort()方法
如何實現陣列與List的相互轉換?
List轉陣列:toArray(arraylist.size()方法;陣列轉List:Arrays的asList(a)方法
List<String> arrayList = new ArrayList<String>();
arrayList.add("s");
arrayList.add("e");
arrayList.add("n");
/**
* ArrayList轉陣列
*/
int size=arrayList.size();
String[] a = arrayList.toArray(new String[size]);
//輸出第二個元素
System.out.println(a[1]);//結果:e
//輸出整個陣列
System.out.println(Arrays.toString(a));//結果:[s, e, n]
/**
* 陣列轉list
*/
List<String> list=Arrays.asList(a);
/**
* list轉Arraylist
*/
List<String> arrayList2 = new ArrayList<String>();
arrayList2.addAll(list);
System.out.println(list);
複製程式碼
如何求ArrayList集合的交集 並集 差集 去重複並集
需要用到List介面中定義的幾個方法:
- addAll(Collection<? extends E> c) :按指定集合的Iterator返回的順序將指定集合中的所有元素追加到此列表的末尾 例項程式碼:
- retainAll(Collection<?> c): 僅保留此列表中包含在指定集合中的元素。
- removeAll(Collection<?> c) :從此列表中刪除指定集合中包含的所有元素。
package list;
import java.util.ArrayList;
import java.util.List;
/**
*TODO 兩個集合之間求交集 並集 差集 去重複並集
* @author 寇爽
* @date 2017年11月21日
* @version 1.8
*/
public class MethodDemo {
public static void main(String[] args) {
// TODO Auto-generated method stub
List<Integer> list1 = new ArrayList<Integer>();
list1.add(1);
list1.add(2);
list1.add(3);
list1.add(4);
List<Integer> list2 = new ArrayList<Integer>();
list2.add(2);
list2.add(3);
list2.add(4);
list2.add(5);
// 並集
// list1.addAll(list2);
// 交集
//list1.retainAll(list2);
// 差集
// list1.removeAll(list2);
// 無重複並集
list2.removeAll(list1);
list1.addAll(list2);
for (Integer i : list1) {
System.out.println(i);
}
}
}
複製程式碼
HashMap 的工作原理及程式碼實現
ConcurrentHashMap 的工作原理及程式碼實現
集合框架底層資料結構總結
- Collection
1. List
- Arraylist:陣列(查詢快,增刪慢 執行緒不安全,效率高 )
- Vector:陣列(查詢快,增刪慢 執行緒安全,效率低 )
- LinkedList:連結串列(查詢慢,增刪快 執行緒不安全,效率高 )
2. Set
- HashSet(無序,唯一):雜湊表或者叫雜湊集(hash table)
- LinkedHashSet:連結串列和雜湊表組成 。 由連結串列保證元素的排序 , 由雜湊表證元素的唯一性
- TreeSet(有序,唯一):紅黑樹(自平衡的排序二叉樹。)
- Map
- HashMap:基於雜湊表的Map介面實現(雜湊表對鍵進行雜湊,Map結構即對映表存放鍵值對)
- LinkedHashMap:HashMap 的基礎上加上了連結串列資料結構
- HashTable:雜湊表
- TreeMap:紅黑樹(自平衡的排序二叉樹)
集合的選用
主要根據集合的特點來選用,比如我們需要根據鍵值獲取到元素值時就選用Map介面下的集合,需要排序時選擇TreeMap,不需要排序時就選擇HashMap,需要保證執行緒安全就選用ConcurrentHashMap.當我們只需要存放元素值時,就選擇實現Collection介面的集合,需要保證元素唯一時選擇實現Set介面的集合比如TreeSet或HashSet,不需要就選擇實現List介面的比如ArrayList或LinkedList,然後再根據實現這些介面的集合的特點來選用。
2018/3/11更新
集合的常用方法
今天下午無意看見一道某大廠的面試題,面試題的內容就是問你某一個集合常見的方法有哪些。雖然平時也經常見到這些集合,但是猛一下讓我想某一個集合的常用的方法難免會有遺漏或者與其他集合搞混,所以建議大家還是照著API文件把常見的那幾個集合的常用方法看一看。
會持續更新。。。
參考書籍:
《Head first java 》第二版 推薦閱讀真心不錯 (適合基礎較差的)
《Java核心技術卷1》推薦閱讀真心不錯 (適合基礎較好的)
《演算法》第四版 (適合想對資料結構的Java實現感興趣的)
歡迎關注我的微信公眾號(分享各種Java學習資源,面試題,以及企業級Java實戰專案回覆關鍵字免費領取):