集合加泛型的常用知識
阿新 • • 發佈:2019-01-27
Collection
/*
* 集合的由來:
* 我們學習的是面嚮物件語言,而面嚮物件語言對事物的描述是通過物件體現的,為了方便對多個物件進行操作,我們就必須把這多個物件進行儲存。
* 而要想儲存多個物件,就不能是一個基本的變數,而應該是一個容器型別的變數,在我們目前所學過的知識裡面,有哪些是容器型別的呢?
* 陣列和StringBuffer。但是呢?StringBuffer的結果是一個字串,不一定滿足我們的要求,所以我們只能選擇陣列,這就是物件陣列。
* 而物件陣列又不能適應變化的需求,因為陣列的長度是固定的,這個時候,為了適應變化的需求,Java就提供了集合類供我們使用。
*
* 陣列和集合的區別?
* A:長度區別
* 陣列的長度固定
* 集合長度可變
* B:內容不同
* 陣列儲存的是同一種類型的元素
* 而集合可以儲存不同型別的元素
* C:元素的資料型別問題
* 陣列可以儲存基本資料型別,也可以儲存引用資料型別
* 集合只能儲存引用型別
*
* 剛說過集合是儲存多個元的,但是呢,儲存多個元素我們也是有不同需求的:比如說,我要這多個元素中不能有相同的元素,
* 再比如說,我要這多個元素按照某種規則排序一下。針對不同的需求,Java就提供了不同的集合類,這樣呢,Java就提供了很多個集合類。
* 這多個集合類的資料結構不同,結構不同不重要的,重要的是你要能夠儲存東西,並且還要能夠使用這些東西,比如說判斷,獲取等。
* 既然這樣,那麼,這多個集合類是有共性的內容的,我們把這些集合類的共性內容不斷的向上提取,最終就能形成集合的繼承體系結構。
*
* 資料結構:資料的儲存方式。
* Collection:是集合的頂層介面,它的子體系有重複的,有唯一的,有有序的,有無序的。(後面會慢慢的講解)
*
* Collection的功能概述:
* 1 :新增功能
* boolean add(Object obj):新增一個元素
* boolean addAll(Collection c):新增一個集合的元素
* 2:刪除功能
* void clear():移除所有元素
* boolean remove(Object o):移除一個元素
* boolean removeAll(Collection c):移除一個集合的元素(是一個還是所有)
* 3:判斷功能
* boolean contains(Object o):判斷集合中是否包含指定的元素
* boolean containsAll(Collection c):判斷集合中是否包含指定的集合元素(是一個還是所有)
* boolean isEmpty():判斷集合是否為空
* 4:獲取功能
* Iterator<E> iterator()(重點)
* 5:長度功能
* int size():元素的個數
* 面試題:陣列有沒有length()方法呢?字串有沒有length()方法呢?集合有沒有length()方法呢?
* 6:交集功能
* boolean retainAll(Collection c):兩個集合都有的元素?思考元素去哪了,返回的boolean 又是什麼意思呢?
* 7:把集合轉換為陣列
* Object[] toArray()
*/
迭代器的原始碼
public interface Inteator {
boolean hasNext();
Object next();
}
public interface Iterable {
Iterator iterator();
}
public interface Collection extends Iterable {
Iterator iterator();
}
public interface List extends Collection {
Iterator iterator();
}
public class ArrayList implements List {
public Iterator iterator() {
return new Itr();
}
private class Itr implements Iterator {
public boolean hasNext() {}
public Object next(){}
}
併發修改異常
/*
* 問題?
* 我有一個集合,如下,請問,我想判斷裡面有沒有"world"這個元素,如果有,我就新增一個"javaee"元素,請寫程式碼實現。
*
* ConcurrentModificationException:當方法檢測到物件的併發修改,但不允許這種修改時,丟擲此異常。
* 產生的原因:
* 迭代器是依賴於集合而存在的,在判斷成功後,集合的中新添加了元素,而迭代器卻不知道,所以就報錯了,這個錯叫併發修改異常。
* 其實這個問題描述的是:迭代器遍歷元素的時候,通過集合是不能修改元素的。
* 如何解決呢?
* A:迭代器迭代元素,迭代器修改元素
* 元素是跟在剛才迭代的元素後面的。
* B:集合遍歷元素,集合修改元素(普通for)
* 元素在最後新增的。
*/
public class ListIteratorDemo2 {
public static void main(String[] args) {
// 建立List集合物件
List list = new ArrayList();
// 新增元素
list.add("hello");
list.add("world");
list.add("java");
// 迭代器遍歷
// Iterator it = list.iterator();
// while (it.hasNext()) {
// String s = (String) it.next();
// if ("world".equals(s)) {
// list.add("javaee"); 錯誤的做法 迭代器是依賴於集合而存在的,在判斷成功後,集合的中新添加了元素,而迭代器卻不知道
// }
// }
// 方式1:迭代器迭代元素,迭代器修改元素
// 而Iterator迭代器卻沒有新增功能,所以我們使用其子介面ListIterator
// ListIterator lit = list.listIterator();
// while (lit.hasNext()) {
// String s = (String) lit.next();
// if ("world".equals(s)) {
// lit.add("javaee");
// }
// }
// 方式2:集合遍歷元素,集合修改元素(普通for)
for (int x = 0; x < list.size(); x++) {
String s = (String) list.get(x);
if ("world".equals(s)) {
list.add("javaee");
}
}
System.out.println("list:" + list);
}}
ArrayList去重的兩種簡單方法
import java.util.ArrayList;
import java.util.Iterator;
/*
* 第一種 建立新的集合
* ArrayList去除集合中字串的重複值(字串的內容相同)
*
* 分析:
* A:建立集合物件
* B:新增多個字串元素(包含內容相同的)
* C:建立新集合
* D:遍歷舊集合,獲取得到每一個元素
* E:拿這個元素到新集合去找,看有沒有
* 有:不搭理它
* 沒有:就新增到新集合
* F:遍歷新集合
*/
public class ArrayListDemo {
public static void main(String[] args) {
// 建立集合物件
ArrayList array = new ArrayList();
// 新增多個字串元素(包含內容相同的)
array.add("hello");
array.add("world");
array.add("java");
array.add("world");
array.add("java");
array.add("world");
array.add("world");
array.add("world");
array.add("world");
array.add("java");
array.add("world");
// 建立新集合
ArrayList newArray = new ArrayList();
// 遍歷舊集合,獲取得到每一個元素
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
// 拿這個元素到新集合去找,看有沒有
if (!newArray.contains(s)) {
newArray.add(s);
}
}
// 遍歷新集合
for (int x = 0; x < newArray.size(); x++) {
String s = (String) newArray.get(x);
System.out.println(s);
}
}
}
import java.util.ArrayList;
import java.util.Iterator;
/*
* 第二種 在原有的集合上操作
* 需求:ArrayList去除集合中字串的重複值(字串的內容相同)
* 要求:不能建立新的集合,就在以前的集合上做。
*/
public class ArrayListDemo2 {
public static void main(String[] args) {
// 建立集合物件
ArrayList array = new ArrayList();
// 新增多個字串元素(包含內容相同的)
array.add("hello");
array.add("world");
array.add("java");
array.add("world");
array.add("java");
array.add("world");
array.add("world");
array.add("world");
array.add("world");
array.add("java");
array.add("world");
// 由選擇排序思想引入,我們就可以通過這種思想做這個題目
// 拿0索引的依次和後面的比較,有就把後的幹掉
// 同理,拿1索引...
for (int x = 0; x < array.size() - 1; x++) {
for (int y = x + 1; y < array.size(); y++) {
if (array.get(x).equals(array.get(y))) {
array.remove(y);
y--;
}
}
}
// 遍歷集合
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}
**注意**
**需求:去除集合中自定義物件的重複值(物件的成員變數值都相同)**
*
* 我們按照和字串一樣的操作,發現出問題了。
* 我們必須思考哪裡會出問題?
* 通過簡單的分析,我們知道問題出現在了判斷上。
* 而這個判斷功能是集合自己提供的,所以我們如果想很清楚的知道它是如何判斷的,就應該去看原始碼。
* contains()方法的底層依賴的是equals()方法。
* 而我們的學生類中沒有equals()方法,這個時候,預設使用的是它父親Object的equals()方法
* Object()的equals()預設比較的是地址值,所以,它們進去了。因為new的東西,地址值都不同。
* 按照我們自己的需求,比較成員變數的值,重寫equals()即可。
* 自動生成即可。
自定義棧集合
import java.util.LinkedList;
/**
* 自定義的棧集合
*/
public class MyStack {
private LinkedList link;
public MyStack() {
link = new LinkedList();
}
public void add(Object obj) {
link.addFirst(obj);
}
public Object get() {
// return link.getFirst();
return link.removeFirst();
}
public boolean isEmpty() {
return link.isEmpty();
}
}
泛型
(1)泛型概述
是一種把明確型別的工作推遲到建立物件或者呼叫方法的時候才去明確的特殊的型別。
(2)格式:
<資料型別>
注意:該資料型別只能是引用型別。
(3)好處:
A:把執行時期的問題提前到了編譯期間
B:避免了強制型別轉換
C:優化了程式設計,解決了黃色警告線問題,讓程式更安全
(4)泛型的前世今生
A:泛型的由來
Object型別作為任意型別的時候,在向下轉型的時候,會隱含一個轉型問題
B:泛型類
C:泛型方法
D:泛型介面
E:泛型高階萬用字元
?
? extends E
? super E
(5)我們在哪裡使用呢?
一般是在集合中使用。
Set集合
(1)Set集合的特點
無序,唯一
(2)HashSet集合(掌握)
A:底層資料結構是雜湊表(是一個元素為連結串列的陣列)
B:雜湊表底層依賴兩個方法:hashCode()和equals()
執行順序:
首先比較雜湊值是否相同
相同:繼續執行equals()方法
返回true:元素重複了,不新增
返回false:直接把元素新增到集合
不同:就直接把元素新增到集合
C:如何保證元素唯一性的呢?
由hashCode()和equals()保證的
D:開發的時候,程式碼非常的簡單,自動生成即可。
E:HashSet儲存字串並遍歷
F:HashSet儲存自定義物件並遍歷(物件的成員變數值相同即為同一個元素)
(3)TreeSet集合
A:底層資料結構是紅黑樹(是一個自平衡的二叉樹)
B:保證元素的排序方式
a:自然排序(元素具備比較性)
讓元素所屬的類實現Comparable介面
b:比較器排序(集合具備比較性)
讓集合構造方法接收Comparator的實現類物件
Collection集合總結
Collection
|--List 有序,可重複
|--ArrayList
底層資料結構是陣列,查詢快,增刪慢。
執行緒不安全,效率高
|--Vector
底層資料結構是陣列,查詢快,增刪慢。
執行緒安全,效率低
|--LinkedList
底層資料結構是連結串列,查詢慢,增刪快。
執行緒不安全,效率高
|--Set 無序,唯一
|--HashSet
底層資料結構是雜湊表。
如何保證元素唯一性的呢?
依賴兩個方法:hashCode()和equals()
開發中自動生成這兩個方法即可
|--LinkedHashSet
底層資料結構是連結串列和雜湊表
由連結串列保證元素有序
由雜湊表保證元素唯一
|--TreeSet
底層資料結構是紅黑樹。
如何保證元素排序的呢?
自然排序
比較器排序
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 姓名長度
int num = s1.getName().length() - s2.getName().length();
// 姓名內容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
: num;
// 年齡
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
});
如何保證元素唯一性的呢?
根據比較的返回值是否是0來決定
常見集合資料結構
ArrayXxx:底層資料結構是陣列,查詢快,增刪慢
LinkedXxx:底層資料結構是連結串列,查詢慢,增刪快
HashXxx:底層資料結構是雜湊表。依賴兩個方法:hashCode()和equals()
TreeXxx:底層資料結構是二叉樹。兩種方式排序:自然排序和比較器排序
Map集合
(1)將鍵對映到值的物件。一個對映不能包含重複的鍵;每個鍵最多隻能對映到一個值。
(2)Map和Collection的區別?
A:Map 儲存的是鍵值對形式的元素,鍵唯一,值可以重複。夫妻對
B:Collection 儲存的是單獨出現的元素,子介面Set元素唯一,子介面List元素可重複。光棍
(3)Map介面功能概述
A:新增功能
V put(K key,V value):新增元素。這個其實還有另一個功能?先不告訴你,等會講
如果鍵是第一次儲存,就直接儲存元素,返回null
如果鍵不是第一次存在,就用值把以前的值替換掉,返回以前的值
B:刪除功能
void clear():移除所有的鍵值對元素
V remove(Object key):根據鍵刪除鍵值對元素,並把值返回
C:判斷功能
boolean containsKey(Object key):判斷集合是否包含指定的鍵
boolean containsValue(Object value):判斷集合是否包含指定的值
boolean isEmpty():判斷集合是否為空
D:獲取功能
Set<Map.Entry<K,V>> entrySet():???
V get(Object key):根據鍵獲取值
Set<K> keySet():獲取集合中所有鍵的集合
Collection<V> values():獲取集合中所有值的集合
E:長度功能
int size():返回集合中的鍵值對的對數
(4)Map集合的遍歷
A:鍵找值
a:獲取所有鍵的集合
b:遍歷鍵的集合,得到每一個鍵
c:根據鍵到集合中去找值
B:鍵值對物件找鍵和值
a:獲取所有的鍵值對物件的集合
b:遍歷鍵值對物件的集合,獲取每一個鍵值對物件
c:根據鍵值對物件去獲取鍵和值
程式碼體現:
Map<String,String> hm = new HashMap<String,String>();
hm.put("it002","hello");
hm.put("it003","world");
hm.put("it001","java");
//方式1 鍵找值
Set<String> set = hm.keySet();
for(String key : set) {
String value = hm.get(key);
System.out.println(key+"---"+value);
}
//方式2 鍵值對物件找鍵和值
Set<Map.Entry<String,String>> set2 = hm.entrySet();
for(Map.Entry<String,String> me : set2) {
String key = me.getKey();
String value = me.getValue();
System.out.println(key+"---"+value);
}
(5)HashMap集合的練習
A:HashMap<String,String>
B:HashMap<Integer,String>
C:HashMap<String,Student>
D:HashMap<Student,String>
(6)TreeMap集合的練習
A:TreeMap<String,String>
B:TreeMap<Student,String>
(7)案例
A:統計一個字串中每個字元出現的次數
B:集合的巢狀遍歷
a:HashMap巢狀HashMap
b:HashMap巢狀ArrayList
c:ArrayList巢狀HashMap
* Hashtable和HashMap的區別?
* Hashtable:執行緒安全,效率低。不允許null鍵和null值
* HashMap:執行緒不安全,效率高。允許null鍵和null值
集合總結
1:集合
Collection(單列集合)
List(有序,可重複)
ArrayList
底層資料結構是陣列,查詢快,增刪慢
執行緒不安全,效率高
Vector
底層資料結構是陣列,查詢快,增刪慢
執行緒安全,效率低
LinkedList
底層資料結構是連結串列,查詢慢,增刪快
執行緒不安全,效率高
Set(無序,唯一)
HashSet
底層資料結構是雜湊表。
雜湊表依賴兩個方法:hashCode()和equals()
執行順序:
首先判斷hashCode()值是否相同
是:繼續執行equals(),看其返回值
是true:說明元素重複,不新增
是false:就直接新增到集合
否:就直接新增到集合
最終:
自動生成hashCode()和equals()即可
LinkedHashSet
底層資料結構由連結串列和雜湊表組成。
由連結串列保證元素有序。
由雜湊表保證元素唯一。
TreeSet
底層資料結構是紅黑樹。(是一種自平衡的二叉樹)
如何保證元素唯一性呢?
根據比較的返回值是否是0來決定
如何保證元素的排序呢?
兩種方式
自然排序(元素具備比較性)
讓元素所屬的類實現Comparable介面
比較器排序(集合具備比較性)
讓集合接收一個Comparator的實現類物件
Map(雙列集合)
A:Map集合的資料結構僅僅針對鍵有效,與值無關。
B:儲存的是鍵值對形式的元素,鍵唯一,值可重複。
HashMap
底層資料結構是雜湊表。執行緒不安全,效率高
雜湊表依賴兩個方法:hashCode()和equals()
執行順序:
首先判斷hashCode()值是否相同
是:繼續執行equals(),看其返回值
是true:說明元素重複,不新增
是false:就直接新增到集合
否:就直接新增到集合
最終:
自動生成hashCode()和equals()即可
LinkedHashMap
底層資料結構由連結串列和雜湊表組成。
由連結串列保證元素有序。
由雜湊表保證元素唯一。
Hashtable
底層資料結構是雜湊表。執行緒安全,效率低
雜湊表依賴兩個方法:hashCode()和equals()
執行順序:
首先判斷hashCode()值是否相同
是:繼續執行equals(),看其返回值
是true:說明元素重複,不新增
是false:就直接新增到集合
否:就直接新增到集合
最終:
自動生成hashCode()和equals()即可
TreeMap
底層資料結構是紅黑樹。(是一種自平衡的二叉樹)
如何保證元素唯一性呢?
根據比較的返回值是否是0來決定
如何保證元素的排序呢?
兩種方式
自然排序(元素具備比較性)
讓元素所屬的類實現Comparable介面
比較器排序(集合具備比較性)
讓集合接收一個Comparator的實現類物件
2:到底使用那種集合
看需求。
是否是鍵值物件形式:
是:Map
鍵是否需要排序:
是:TreeMap
否:HashMap
不知道,就使用HashMap。
否:Collection
元素是否唯一:
是:Set
元素是否需要排序:
是:TreeSet
否:HashSet
不知道,就使用HashSet
否:List
要安全嗎:
是:Vector(其實我們也不用它,後面我們講解了多執行緒以後,我在給你回顧用誰)
否:ArrayList或者LinkedList
增刪多:LinkedList
查詢多:ArrayList
不知道,就使用ArrayList
不知道,就使用ArrayList
3:集合的常見方法及遍歷方式
Collection:
add()
remove()
contains()
iterator()
size()
遍歷:
增強for
迭代器
|--List
get()
遍歷:
普通for
|--Set
Map:
put()
remove()
containskey(),containsValue()
keySet()
get()
value()
entrySet()
size()
遍歷:
根據鍵找值
根據鍵值對物件分別找鍵和值