集合深入理解
集合:用於存儲對象,長度可變,可存儲不同類型元素
框架結構:
Collection:
Set:無序,元素不可重複
常見子類:
| ——HashSet 底層數據結構是哈希表
1, 通過hashCode和equals方法判斷對象是否相等
2,如果元素hashCode值不同,不會調用equals方法
3,HashCode值相同纔會接着調用equals方法去判斷
|——TreeSet 底層數據結構是二叉樹
可以對Set集合元素進行排序
List:有序,元素可重複,因爲該集合有索引
|—— ArrayList:底層是數組結構,查詢速度快。線程不同步,效率高。初始長度10
可變長度原理:通過不斷new數組,長度是50%延長,將原數組copy到新數組,再接着添加新元素
|—— LinkedList:底層是鏈表,增刪數度快,查詢慢
|—— Vector:底層是數組結構。線程同步。延長100%
Java1.6新加入了Deque來代替Vector下的Stack類
Map 以鍵值對的形式存值
|—— HashTable 底層是哈希表結構,不可存入null鍵null值,線程同步
|—— HashMap 底層是哈希表結構,允許使用null值和null鍵,不同步,效率高
|—— TreeMap 二叉樹,紅黑樹,不同步,根據鍵 排序
Collections
工具類,不提供構造函數,不能創建對象,提供static方法對集合進行操作
如:排序,synchronizedListList()方法,將普通集合包裝成線程安全的
Set和Map的關係:
Map的所有鍵key集中在一起就是一個Set集合,Map集合中有一個keySet()方法,就是返回key所組成的Set集合
如果將value值看作key的一個附屬屬性的話,key-value組合起來,也是形成一個Set集合,Map.Entry是一個內部接口
Set集合如果存入的數據是Map.Entry形式,可以擴展成Map集合
注意:雖然說集合中存儲的是java對象,但是實際上集合中存儲的還是對對象的引用
如下:
import java.util.ArrayList;
import java.util.List;
class Apple {
private double weight;
public Apple(double weight) {
this.weight = weight;
}
}
public class ListTest {
public static void main(String[] args) {
Apple a = new Apple(1.1);
Apple a2 = new Apple(2.2);
List<Apple> list = new ArrayList<Apple>();
list.add(a);
list.add(a2);
// 輸出true說明集合中的變量和a引用指向同一個對象
System.out.println(list.get(0) == a);
}
}
HashMap和HashSet
向hashSet集合中裝東西時,重寫equals方法和hashCode方法非常重要
如下:
import java.util.HashSet;
class Stuff {
private String id;
private int age;
public Stuff(String id, int age) {
this.id = id;
this.age = age;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj.getClass() == Stuff.class) {
Stuff s = (Stuff) obj;
return s.id.equals(id);
}
return false;
}
public int hashCode() {
// id唯一,根據返回id屬性的哈希值
return id.hashCode();
}
public String toString() {
return "id:" + id + ",age:" + age;
}
}
public class HashSetTest {
public static void main(String[] args) {
HashSet<Stuff> hs = new HashSet<Stuff>();
hs.add(new Stuff("ks123", 22));
// 根據自己寫的hashCode方法,此處會判斷第二個對象和第一個對象一樣,所以不能重複添加
hs.add(new Stuff("ks123", 23));
System.out.println(hs);
}
}
Map和List
Map集合中的value集中起來就是一個list集合,通過map.values()方法可得到所有value數據
Values()源代碼
public Collection<V> values(){
// 獲取values實例變量
Collection<v> vs = values;
// 如果vs == null,將返回new Values()對象
return (vs!=null?vs:new Values());
}
可以看出,返回的並不是list集合對象
ArrayLsit和LinkedList
ArrayList的性能總體上來說還是高於LinkedList
在查詢元素時,因爲ArrayList是數組結構,有索引,比較好找
在刪除和增加元素時,ArrayList需要對元素整體移動,所以LinkedList更優
迭代器Iterator接口
Java要求各種集合都提供一個iterator()方法,該方法返回一個Iterator用於遍歷集合中的元素,至於返回的Iterator到底是哪種實現類,程序並不關心,這就是”迭代器模式”;
如:Iterator和Enumeration兩個接口都是迭代器模式的代表作,他們就是“迭代器接口”。
迭代器模式就是指:系統爲遍歷多種數據列表,集合,容器提供一個標準的“迭代器接口”,這些數據列表,集合,容器就可面向相同的“迭代器接口”編程,通過相同的迭代器接口訪問不同的數據列表,集合,容器裏的數據。不同的數據列表,集合,容器如何實現這個“迭代器接口”,則交給個數據列表,集合,容器自己完成
迭代時刪除指定元素
由於Iterator迭代器只負責迭代,自己並沒有保留集合元素,所以通常迭代時不應該刪除集合元素,但是java允許通過Iterator的remove()方法刪除剛剛迭代的元素。
實際上在某些特殊情況下,可以在使用Iterator迭代集合時直接刪除集合中某個元素
如下:在迭代倒數第二個元素時,可以刪除該元素,但是刪除其他元素就會拋異常
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListRemove {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
list.add("itheima");
list.add("cloud");
list.add("thythm");
list.add("zhangsan");
for (Iterator<String> it = list.iterator(); it.hasNext();) {
String ele = it.next();
System.out.println(ele);
if ("thythm".equals(ele)) {
// 直接刪除集合中的倒數第二個元素
list.remove(ele);
}
}
}
}
對於TreeSet,HashSet等Set集合而言,當使用Iterator遍歷他們時,如果正在遍歷最後一個集合元素,那麼使用Set集合的remove()方法刪除集合的任何元素不會引起異常
實際上此時的刪除動作已經在遍歷操作的範圍外了