集合框架—–Collection和Map
記錄一下學習的集合框架,梳理思路,也便於以後的查看。如果有錯誤之處,還望大家不吝指出,多謝哈。
集合框架之Collection
來張Collection體系圖:
Collection概述:
Collection是最基本的集合接口,一個Collection代表一組Object,即Collection的元素(Elements)。一些Collection允許相同的元素而另一些不行。一些能排序而另一些不行。Java SDK不提供直接繼承自Collection的類,Java SDK提供的類都是繼承自Collection的“子接口”如List和Set。
所有實現Collection接口的類都必須提供兩個標準的構造函數:無參數的構造函數用於創建一個空的Collection,有一個Collection參數的構造函數用於創建一個新的Collection,這個新的Collection與傳入的Collection有相同的元素。後一個構造函數允許用戶複製一個Collection。
List
- 集合中存取的元素有序(存和取的順序一致),有索引,可以存儲重複值。
Set
- 集合中存取的元素無序(存和取的順序不一致),無索引,不可以存儲重複的值。
注意:因爲List和Set都是Collection的子接口,如果想使用接口,就必須使用它的實現類。如:
List list = new Arraylist();
Collection集合遍歷
- 1,將集合轉換成數組,(利用
toArray()
方法 )再使用for循環遍歷即可。 2,迭代器遍歷(使用集合中
iterator()
方法獲得Iterator對象)- 僞代碼如下:
Iterator it = list.iterator(); //獲取Iterator 對象 while(it.hasNext()) { //判斷集合中是否還有元素 it.next(); //得到元素值 }
- 僞代碼如下:
3,增強for循環遍歷
- 僞代碼如下
Collection c = new ArrayList(); //Object obj = new Student("張三",23); c.add(new Student("張三",23)); //Object obj = new Student("張三",23); 這裏會自動類型提升爲Object c.add(new Student("李四",24)); c.add(new Student("王五",25)); c.add(new Student("馬六",26)); for (Object value : c) { System.out.println(value); }
- 1,將集合轉換成數組,(利用
List集合特有的遍歷
- 1,根據List集合的特點:有索引,可以通過
list.get(int index);
方法遍歷 - 2,List特有的方法:ListIterator。根據
listIterator()
方法獲得ListIterator迭代器對象。
- 1,根據List集合的特點:有索引,可以通過
集合遍歷注意事項
- 當使用Iterator迭代器遍歷集合需要增添或修改元素時,很可能會發生併發修改異常(ConcurrentModificationException)。
- 原因:當遍歷集合時,增添或修改集合中元素,使用的是集合的方法,而迭代器並不知道,這就導致出現了併發修改異常。
- 解決辦法:
- 1,使用普通for循環(通過索引刪除,一個集合的最大索引爲:list.size() - 1; 注意:索引要字減一)list.remove(index–);
- 2,使用ListIterator迭代器,因爲此迭代器中特有添加和刪除的方法。
- 當使用Iterator迭代器遍歷集合需要增添或修改元素時,很可能會發生併發修改異常(ConcurrentModificationException)。
List集合中三個子類的特點
- ArrayList:底層數據結構是數組,查詢修改快,增刪慢,線程不安全,但效率高。
- Vector:底層數據結構是數組,查詢修改增刪都慢,線程安全,但效率低。
- LinkedList:底層數據結構是鏈表,查詢修改慢,增刪快,線程不安全,但效率高。
- 結論:
- 查詢多用ArrayList
- 增山多用LinkedList
- 都多用Arraylist
泛型
- 如:
Collection<String> c = new Arraylist<>();
定義了一個泛型爲String類型的集合。 - 使用泛型的好處:
- 提高安全性(將運行期的錯誤轉換到編譯期)
- 省去強轉的麻煩
- 注意:
- <>中放的必須是引用數據類型。
- 前後的泛型必須一致,或者後面的泛型可以省略不寫(JDK1.7新特性,菱形泛型)
- 泛型最好不要定義成Object,沒有意義。
- 如:
- HashSet集合類(Set集合的實現類)
- 特點:
- 方法和Collection中方法一樣
- 當向Set集合中存儲重複元素時,返回值爲false
- HashSet的繼承體系中有重寫toString方法
- HashSet存儲自定義對象:
- 爲了保證元素的唯一性,自定義對象的類中必須重寫hashCode()和equals()方法。
- 當哈希值一樣時,纔會調用equals()方法。
- 爲了保證元素的唯一性,自定義對象的類中必須重寫hashCode()和equals()方法。
- 特點:
- LinkedHashSet集合類(HashSet的子類)
- 特點:
- 底層是鏈表實現的,是Set集合中唯一保證怎麼存就怎麼取。
- 該類是HashSet的子類,所以也是保證元素唯一的,與HashSet的原理一樣。
- 特點:
- TreeSet集合類(Set集合的實現類)
- 特點:
- 保證元素的唯一性
- 可以對元素進行排序
- 排序的方式(自定義對象時)
- 自然排序:自定義對象的類需要實現Compareable接口,並重寫接口中compareTo()方法。
- 在TreeSet集合類中如何存儲元素取決於compareTo()方法的返回值:
- 返回值爲0:集合中只會存儲一個元素。
- 返回值爲正數:集合怎麼存,就會怎麼輸出。
- 返回值爲負數:集合會將存儲的元素倒序輸出。
- 來個自然排序的代碼:
- 在TreeSet集合類中如何存儲元素取決於compareTo()方法的返回值:
- 自然排序:自定義對象的類需要實現Compareable接口,並重寫接口中compareTo()方法。
- 特點:
//自定義對象,Person類
public class Person implements Comparable<Person>{
private String name;
private int age;
public Person() {
super();
}
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;
}
@Override
//按照年齡排序
public int compareTo(Person p) {
//排序:如果是新的(後進來的)減去老的(先進來的),是從小到大排序。
// 如果是老的減去新的,就是從大到小排序
// this代表新的,p代表老的
int num = this.age - p.age; //判斷年齡是否相同
//當年齡相同是,比較姓名是否相同。
int num2 = num == 0 ? this.name.compareTo(p.name) : num;
return num2;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
//測試類
import java.util.TreeSet;
public class TreeSetTest {
/**
* 演示
* 按年齡的大小排序(按年齡從小到大排序)
* TreeSet存儲自定義對象並遍歷(按年齡從小到大排序)
*/
public static void main(String[] args) {
TreeSet<Person> ts = new TreeSet<>();
ts.add(new Person("zhangsan", 23));
ts.add(new Person("lisi", 16));
ts.add(new Person("wangwu", 24));
ts.add(new Person("zhaoliu", 34));
ts.add(new Person("aaaa", 44));
System.out.println(ts);
}
}
//輸出結果:
/*
[Person [name=lisi, age=16],
Person [name=zhangsan, age=23],
Person [name=wangwu, age=24],
Person [name=zhaoliu, age=34],
Person [name=aaaa, age=44]]
*/
比較排序:Comparator以內部類的形式實現。
代碼如下:
//自定義對象Person類
public class Person {
private String name;
private int age;
public Person() {
super();
}
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
//測試類
import java.util.Comparator;
import java.util.TreeSet;
public class Test5_1 {
/**
* 演示
* TreeSet存儲自定義對象並遍歷(按照姓名的長度排序)
*/
public static void main(String[] args) {
//利用比較器排序(匿名內部類)
TreeSet<Person> ts = new TreeSet<>(new Comparator<Person>() {
@Override
public int compare(Person p1, Person p2) {
int length = p1.getName().length() - p2.getName().length();
int num2 = length == 0 ? p1.getName().compareTo(p2.getName()) : length;
return num2 == 0 ? p1.getAge() - p2.getAge() : num2;
}
});
ts.add(new Person("zhangsan", 23));
ts.add(new Person("lisi", 25));
ts.add(new Person("wangwu", 26));
ts.add(new Person("zhaoliu", 28));
ts.add(new Person("aaaa", 36));
System.out.println(ts);
}
}
//輸出結果
/*
[Person2 [name=aaaa, age=36],
Person2 [name=lisi, age=25],
Person2 [name=wangwu, age=26],
Person2 [name=zhaoliu, age=28],
Person2 [name=zhangsan, age=23]]
*/
集合框架之Map
來張Map體系圖:
- Map概述:
- 請注意,Map沒有繼承Collection接口,Map提供key到value的映射。一個Map中不能包含相同的key,每個key只能映射一個value。Map接口提供3種集合的視圖,Map的內容可以被當作一組key集合,一組value集合,或者一組key-value映射。
- Map接口和Collection的區別:
- 1,Map接口是雙列,而Collection接口是單列。
- 2,Map體系中鍵是唯一的,Collection的子體系Set是唯一的。
- 3,Map集合的數據結構的值針對鍵有效,跟值無關。Collection集合的數據結構是針對元素有效。
- Map存儲鍵值時:
- 代碼演示,僞代碼如下:
Map<String,Integer> map = new HashMap<>();
Integer i1 = map.put("張三",23); //返回值爲null
Integer i2 = map.put("李四",24); //返回值爲null
Integer i2 = map.put("張三",30); //返回值爲23(出現相同鍵值對時,不會存儲,會覆蓋原來的鍵值對。)
System.out.println(map);
//輸出結果
/*
{張三=30, 李四=24}
*/
- Map集合遍歷
**注意:**Map集合中沒有迭代器
- A :
- 1,根據鍵獲取值:首先獲取所有鍵的集合(
Set<> set keySet = map.keySet();
)接下來就可以使用迭代器了,根據鍵獲取值(map.get(key);
) - 2,增強for循環遍歷(和第一種方法相似)
-for(k ,key : map.keySet()) { System.out.println(key + " = " + map.get(key));}
- 1,根據鍵獲取值:首先獲取所有鍵的集合(
- B:根據鍵值對 對象,獲取鍵和值。
- 利用entrySet()方法,獲得鍵值對 對象,得到一個Set集合。遍歷Set集合。
- 代碼如下(來個完整版的):
- A :
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class MapEntry {
/**
* map遍歷:
* 根據鍵值對 對象,獲取鍵和值。
*/
public static void main(String[] args) {
Map<String ,Integer> map = new HashMap<String, Integer>();
map.put("張三", 23);
map.put("李四", 24);
map.put("王五", 25);
map.put("趙六", 26);
map.put("馬奇", 27);
//利用entrySet()方法獲取鍵值對 對象 得到一個set集合(以下兩種寫法,均可)
//Map.Entry 這是Map接口內又寫了Entry接口
Set<Map.Entry<String,Integer>> set = map.entrySet();
//Set<Entry<String,Integer>> set = map.entrySet();
//遍歷鍵值對 對象 set集合
for (Entry<String, Integer> entry : set) {
String key = entry.getKey(); //通過鍵值對 對象 的getKey方法獲得鍵
Integer value = entry.getValue(); //返回與此項對應的值。
System.out.println(key + "=" + value);
}
}
}
- HashMap集合類
- 注意:存儲自定義對象時,和HashSet一樣,需要重寫hashCode()和equals()方法。(鍵 是自定義對象,值 是引用數據類型)
- LinkedHashMap集合類
- 和LinkedHashSet原理一樣。
- TreeMap集合類
- 和TreeMap原理一樣。
- (面試題)HashMap和Hashtable的區別:
- 共同點: 底層都是哈希算法,都是雙列集合
- 不同點:
- A:
- 1,HashMap是線程不安全的,效率高,JDK1.2版本
- 2,Hastable是線程安全的,效率低,JDK1.0版本
- B:
- 1,HashMap可以存儲null鍵和值
- 2,Hastable不可以存儲null鍵和值
- A: