Java 基礎 -- 集合框架
阿新 • • 發佈:2019-01-25
集合
1. Java集合框架
1.1 簡介
- Java類庫中, 集合類的基本介面是: Collection介面和Map介面
- Collection是元素集合, Map是鍵值對(key-value)
- Collection介面有兩個基本兩個方法:
- boolean add(E element); 向集合中新增元素
- Iterator iterator(); 返回一個迭代器, 用於訪問集合中的物件
- Iterator介面中有兩個常用方法:
- E next(); 反覆呼叫可以逐個訪問集合中每個元素
- boolean hasNext(); 判斷是否還有元素, 用在呼叫next() 方法之前
- Map介面常用方法:
- V put(K key, V value);
- V get(K key);
1.2 Collection常用方法:
- int size();
- boolean isEmpty();
- boolean contains(Object o);
- boolean containsAll(Collection c);
- boolean add(Object o);
- boolean addAll(Collection
1.3 Iterator常用方法
- boolean hasNext(); 判斷是否還存在可訪問的元素
- E next(); 返回將要訪問的下一個物件, 如果已經到達集合尾部, 會丟擲: NoSuchElementException
- void remove(); 刪除上次訪問的物件, 必須緊跟在next()方法後
2. 具體的集合: 主要是以下介面的實現
- List: 序列
- Set: 集
- Map: 字典
2.1 常用的具體集合
- ArrayList: 可以動態增長和縮減的索引序列
- LinkedList: 一種可以在任何位置進行高效插入刪除的有序序列
- HashSet: 沒有重複元素的無序集合
- TreeSet: 一種有序集
- HashMap: 一種儲存 鍵值對的資料結構
- TreeMap: 一種有序排列的鍵值對錶
2.2 List的分析:
- ArrayList: 基於陣列實現, 陣列存在索引, 所以查詢和更改效率高, 刪除和指定位置新增效率低
- LinkedList: 基於雙向連結串列實現, 刪除和新增元素效率高, 查詢和更改效率低
- Vector: 執行緒安全的ArrayList, 在同步操作上會耗費大量時間
- 示例程式碼:
package cn.kuang.java_primary.collection;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.ListIterator;
/**
* 1. 簡單的建立兩個連結串列, 合併在一起
*
* 2. 從第二個連結串列每隔一個元素刪除一個元素
*
* 3. 繪製一個迭代器位置示意圖
*
* Created by 框 on 2018/6/18.
*/
public class LinkedListTest {
public static void main(String[] args) {
// create linkedList a and b
List<String> a = new LinkedList<>();
a.add("tom");
a.add("bob");
a.add("amy");
List<String> b = new LinkedList<>();
b.add("Carl");
b.add("doug");
b.add("france");
b.add("eric");
System.out.println(a);
System.out.println(b);
//merge the words from b into a
ListIterator<String> aIter = a.listIterator();
Iterator<String> bIter = b.iterator();
while (bIter.hasNext()){
if (aIter.hasNext()) aIter.next();
aIter.add(bIter.next());
}
System.out.println(a);
//remove every second word from b
bIter = b.iterator();
while (bIter.hasNext()){
bIter.next();
if (bIter.hasNext()){
bIter.next();
bIter.remove();
}
}
System.out.println(b);
//bulk operation : remove all words in b from a
a.removeAll(b);
System.out.println(a);
}
}
2.3 Set的分析:
- 不在意元素的順序, 可以快速查詢到元素
- 散列表: 為每個物件呼叫HashCode返回一個雜湊碼,
- 常用HashSet, 實現基於散列表的集
- HashSet特點: 無序, 沒有重複元素
- 示例程式碼:
package cn.kuang.java_primary.collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Scanner;
import java.util.Set;
/**
* 1. 從System.in讀取單詞
*
* 2. 把他們新增到HashSet中
*
* 3. 遍歷HashSet中的不同單詞
*
* 4. 打印出單詞數量
*
* Created by 框 on 2018/6/19.
*/
public class SetTest {
public static void main(String[] args) {
Set<String> words = new HashSet<>();
long totalTime = 0;
try(Scanner in = new Scanner(System.in);) {
while (in.hasNext()){
String word = in.next();
long callTime = System.currentTimeMillis();
words.add(word);
callTime = System.currentTimeMillis() - callTime;
totalTime += callTime;
}
}
Iterator<String> iter = words.iterator();
for (int i = 0; i < 20 && iter.hasNext(); i++) {
System.out.println(iter.next());
}
System.out.println("......");
System.out.println(words.size() + " distinct words. " + totalTime + " milliseconds");
}
}
- TreeSet: 是一個有序的集合, 使用紅黑樹實現
- TreeSet特點: 新增元素比HashSet慢, 但是元素有序, 任意兩個元素必須是可比的
- 示例程式碼:
package cn.kuang.java_primary.collection.pojo;
import java.util.Objects;
/**
* Item 實體類
*
* Created by 框 on 2018/6/19.
*/
public class Item implements Comparable<Item> {
private String description;
private int partNumber;
/**
* 有參構造器
* @param description description
* @param partNumber partNumber
*/
public Item(String description, int partNumber) {
this.description = description;
this.partNumber = partNumber;
}
/**
* Gets of description
* @return description
*/
public String getDescription() {
return description;
}
@Override
public String toString() {
return "Item[" + "description='" + description + '\'' + ", partNumber=" + partNumber + ']';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Item)) return false;
Item item = (Item) o;
if (partNumber != item.partNumber) return false;
return description != null ? description.equals(item.description) : item.description == null;
}
@Override
public int hashCode() {
return Objects.hash(description, partNumber);
}
@Override
public int compareTo(Item o) {
int diff = Integer.compare(partNumber, o.partNumber);
return diff != 0 ? diff : description.compareTo(o.description);
}
}
--------------------------------------------------------------------------
package cn.kuang.java_primary.collection;
import cn.kuang.java_primary.collection.pojo.Item;
import java.util.Comparator;
import java.util.NavigableSet;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* 1. 建立兩個Item物件的樹集
*
* 2. 第一個按照部件編號排序: Item物件的預設順序
*
* 3. 第二個通過一個定製的比較器按照描述資訊排序
*
* Created by 框 on 2018/6/19.
*/
public class TreeSetTest {
public static void main(String[] args) {
SortedSet<Item> parts = new TreeSet<>();
parts.add(new Item("Toaster", 1234));
parts.add(new Item("Widget", 4562));
parts.add(new Item("Modem", 9912));
System.out.println(parts);
NavigableSet<Item> sortByDescription = new TreeSet<>(Comparator.comparing(Item::getDescription));
sortByDescription.addAll(parts);
System.out.println(sortByDescription);
}
}
3. 對映/字典
3.1 基本對映操作
- Java類庫提供了兩個通用的實現: HashMap和TreeMap,
- HashMap對鍵進行雜湊, TreeMap用鍵的整體順序對元素進行排序
- 使用HashMap: 不需要按照排列順序訪問鍵
- 示例程式碼:
package cn.kuang.java_primary.collection.pojo;
/**
* Employee實體類
* Created by 框 on 2018/6/19.
*/
public class Employee {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return name ;
}
public Employee() {
}
public Employee(String name) {
this.name = name;
}
}
---------------------------------------------------------
package cn.kuang.java_primary.collection;
import cn.kuang.java_primary.collection.pojo.Employee;
import java.util.HashMap;
import java.util.Map;
/**
* 1. 展示對映的操作過程
*
* 2. 將鍵值對新增到對映中
*
* 3. 刪除一個鍵, 對應的值也會刪除
*
* 4. 修改和檢視某個值
*
* Created by 框 on 2018/6/19.
*/
public class MapTest {
public static void main(String[] args) {
Map<String, Employee> staff = new HashMap<>();
staff.put("114-25-5412", new Employee("Amy qw"));
staff.put("114-25-3234", new Employee("RQs dfg"));
staff.put("114-25-5818", new Employee("EAQ aas"));
staff.put("114-25-9172", new Employee("Asd asd"));
//print staff
System.out.println(staff);
//remove an entity by key
staff.remove("114-25-9172");
//replace an entity
staff.put("114-25-3234", new Employee("Alice"));
//get entity by key
System.out.println(staff.get("114-25-5818"));
//iterate through all entities
staff.forEach(
(k, v) -> System.out.println("key: " + k + " , value = " + v)
);
}
}
3.2 Map常用方法
- V get();
- dafault V getOrDefault(Object key, V defaultValue);
- V put(K key, V value);
- void putAll(Map
4. 一些其他的問題
4.1 HashMap的排序問題
已知一個HashMap<Integer, User>,
User有name, age屬性,
編寫一個方法實現HashMap的排序,
引數為: HashMap<Integer, User>,
返回排好序的HashMap,
排序規則: 按照User的age進行倒序排序, 不得拆散鍵值對
--------------------------------------Class User-----------------------
package cn.kuang.java_primary.collection.pojo;
/**
* HashMapSort的pojo
* Created by 框 on 2018/6/19.
*/
public class User {
private String name;
private int 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;
}
public User() {
}
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" + "name='" + name + '\'' + ", age=" + age + '}';
}
}
--------------------------------------Class sort-----------------------
package cn.kuang.java_primary.collection;
import cn.kuang.java_primary.collection.pojo.User;
import java.util.*;
/**
* 已知一個HashMap<Integer, User>,
*
* User有name, age屬性,
*
* 編寫一個方法實現HashMap的排序,
*
* 引數為: HashMap<Integer, User>,
*
* 返回排好序的HashMap,
*
* 排序規則: 按照User的age進行倒序排序, 不得拆散鍵值對
*
* *************************************************************
* 思路:
* 使用HashMap的子類: LinkedHashMap, 他是Map結構, 也是連結串列結構
*
* 返回LInkedHashMap即可, 還滿足面向介面程式設計
*
* 排序演算法使用JDK中有的API
*
* Created by 框 on 2018/6/19.
*/
public class HashMapSort {
public static void main(String[] args) {
HashMap<Integer, User> hashMap = new HashMap<>();
hashMap.put(1, new User("張三", 17));
hashMap.put(2, new User("李四", 18));
hashMap.put(4, new User("王二", 19));
hashMap.put(3, new User("麻子", 20));
System.out.println("排序前: "+hashMap);
System.out.println("排序後: "+sortHashMapByUserAge(hashMap));
}
public static HashMap<Integer, User> sortHashMapByUserAge(HashMap<Integer, User> map) {
//首先拿到Map的鍵值對幾個
Set<Map.Entry<Integer, User>> entrySet = map.entrySet();
//吧set轉為List集合, 方便實用sort方法
List<Map.Entry<Integer, User>> list = new ArrayList<>(entrySet);
//Collections的sort方法進行排序
Collections.sort(list, new Comparator<Map.Entry<Integer, User>>() {
@Override
public int compare(Map.Entry<Integer, User> o1, Map.Entry<Integer, User> o2) {
//根據User的age進行排序 倒序
return o2.getValue().getAge() - o1.getValue().getAge();
}
});
//建立一個LinkedHashMap
LinkedHashMap<Integer, User> linkedHashMap = new LinkedHashMap<>();
//吧list的資料存進去
for (Map.Entry<Integer, User> entry : list){
linkedHashMap.put(entry.getKey(), entry.getValue());
}
return linkedHashMap;
}
}
4.2 集合的安全性問題
- Vector 和 HashTable是執行緒安全的, 他們的和新方法都添加了 synchronized關鍵字
- ArrayList, HashSet, HashMap是執行緒不安全的
- 可以使用以下方法來是的他們變成執行緒安全的
- Collections.synchronizedCollection(c);
- Collections.synchronizedList(list);
- Collections.synchronizedMap(map);
- Collections.synchronizedSet(set);
4.3 ArrayList內部實現
- 基於Object陣列實現
- 提供了空構造器和兩個帶參構造器
- 構造器1: 引數為int n, 對n進行判斷, 如果n合法, 返回一個長度為 n 的ArrayList
- 構造器2: 引數為一個Collection, 對collection進行判斷, collection不為空, 則吧這個collection轉為陣列a, 並賦值成成員變數array, 陣列長度作為成員變數size
- 提供add方法兩個:
- 首先判斷新增元素後collection容量是否還夠, 不夠就擴容, 夠就新增
- 未指定位置: 將新元素新增到collection的末尾
- 指定位置: 判斷位置是否合法, 合法將新元素新增到指定位置, 其後的元素位置往後挪1
- remove:按照索引來刪除:
- 首先判斷索引位置是否合法, 合法則將該索引的元素刪除
- 之後的整體往前移動一位, 將最後一個元素設定為null, 不然容易記憶體洩漏
4.4 併發集合和普通集合問題
- 併發集合: 常見的:
- ConcurrentHashMap, ConcurrentLinkedQueue, ConcurrentLinkedDeque
- 都是位於 java.util.concurrent下,
- Java中有普通集合, 同步集合, 併發集合
- 普通集合效率高但是不能保證執行緒安全, 併發可靠
- 同步集合僅僅新增同步鎖, 嚴重犧牲了效能, 併發效率低
- 併發集合既保證多執行緒的安全, 又提高了併發效率
4.5 List三個子類特點
- ArrayList 底層結構是陣列,底層查詢快,增刪慢。
- LinkedList 底層結構是連結串列型的,增刪快,查詢慢。
- voctor 底層結構是陣列執行緒安全的,增刪慢,查詢慢。
4.6 List, Map, Set的區別
- 結構特點:
- List和set 都是儲存單列資料的集合, Map是儲存鍵值的雙列資料集合
- List有序可重複, Set無序不重複(位置又元素HashCode決定, 所以不能重複), Map, Key值必須唯一
- 實現類:
- List有三個實現類:
- ArrayList, 陣列實現, 查詢更改快, 增刪慢
- LinkedList, 雙向連結串列實現, 查詢更改慢, 增刪快
- Vector, 執行緒安全, 效率低
- Set實現類:
- HashSet, 底層是HashMap實現,
- LinkedHashSet, 繼承HashSet, 基於LinkedHashMap實現
- Map實現類:
- HashMap, 執行緒不安全, 高效, 鍵值都支援null
- HashTable, 執行緒安全, 不高效, 鍵值都不支援null
- LinkedHashMap, 是HashMap的子類, 儲存插入的順序
- List有三個實現類:
4.7 HashMap和HashTable區別
- HashMap, 執行緒不安全, 高效, 鍵值都支援null
- HashTable, 執行緒安全, 不高效, 鍵值都不支援null
4.8 陣列和連結串列的適用場景
- ArrayList 和Vector 使用了陣列的實現,可以認為ArrayList 或者Vector 封裝了對內部陣列的操作,比如向陣列中新增,刪除,插入新的元素或者資料的擴充套件和重定向。
- LinkedList 使用了迴圈雙向連結串列資料結構。與基於陣列的ArrayList 相比,這是兩種截然不同的實現技術,這也決定了它們將適用於完全不同的工作場景
- 陣列應用場景:資料比較少;經常做的運算是按序號訪問資料元素;陣列更容易實現,任何高階語言都支援的線性表較穩定。
- 連結串列應用場景:對線性表的長度或者規模難以估計;頻繁做插入刪除操作;構建動態性比較強的線性表。
4.9 List a = new ArrayList(); 和 ArrayList a = new ArrayList的區別
- List list = new ArrayList();這句建立了一個ArrayList 的物件後把上溯到了List。此時它是一個List 物件了,有些ArrayList 有但是List 沒有的屬性和方法,它就不能再用了。
- 而ArrayList list=new ArrayList();建立一物件則保留了ArrayList 的所有屬性。所以需要用到ArrayList 獨有的方法的時候不能用前者。
package cn.kuang.java_primary.collection;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.Queue;
/**
* 使用佇列模擬堆疊結構
*
* 佇列a, b
*
* 思路:
*
* 1. 入棧: a, b佇列為空, 將 "a, b, c, d, e" 先放入a中, a中為: "a, b, c, d, e"
*
* 2. 出棧: 將a中元素倒序放入b佇列中, 再將b出列
*
* Created by 框 on 2018/6/19.
*/
public class SimulationStack {
public static void main(String[] args) {
Queue<String> queue = new LinkedList<>(); //a 佇列
Queue<String> queue2=new LinkedList<>(); //b佇列
ArrayList<String> a=new ArrayList<>(); //arrylist集合是中間引數
//往a佇列新增元素
queue.offer("a");
queue.offer("b");
queue.offer("c");
queue.offer("d");
queue.offer("e");
System.out.print("進棧:");
//a佇列依次加入list集合之中
for(String q : queue){
a.add(q);
System.out.print(q);
}
//以倒序的方法取出(a佇列依次加入list集合)之中的值,加入b對列
for(int i=a.size()-1;i>=0;i--){
queue2.offer(a.get(i));
}
//打印出棧佇列
System.out.println("");
System.out.print("出棧:");
for (String q : queue2) {
System.out.print(q);
}
}
}
4.12 遍歷問題
Map遍歷:
package cn.kuang.java_primary.collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Map 的遍歷方法
*
* 1. 獲取所有key來按照key遍歷
*
* 2. 通過Map.entrySet使用iterator遍歷key和value
*
* 3. 通過Map.entrySet遍歷key和value,推薦,尤其是容量大時
*
* 4. 通過Map.values()遍歷所有的value,但不能遍歷key
*
* Created by 框 on 2018/6/19.
*/
public class MapTranverse {
public static void main(String[] args) {
Map<Integer, String> map = new HashMap<>();
map.put(1, "tom");
map.put(2, "noOn");
map.put(3, "wha");
map.put(4, "oepra");
map.put(5, "power");
map.put(6, "eric");
map.put(7, "alic");
map.put(8, "qwe");
//1. 獲取key來遍歷
for (Integer in : map.keySet()) {
String str = map.get(in);
System.out.println(in+ " : " +str);
}
System.out.println("...................................");
//2. 通過Map.entrySet使用iterator遍歷key和value
Iterator<Map.Entry<Integer, String>> it = map.entrySet().iterator();
while (it.hasNext()){
Map.Entry<Integer, String> entry = it.next();
System.out.println(entry.getKey()+" : "+entry.getValue());
}
System.out.println("...................................");
//3. 通過Map.entrySet遍歷key和value,推薦,尤其是容量大時
for (Map.Entry<Integer, String> entry : map.entrySet()) {
System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue());
}
System.out.println("...................................");
//4. 通過Map.values()遍歷所有的value,但不能遍歷key
for (String v : map.values()) {
System.out.println("value= " + v);
}
}
}
List遍歷
package cn.kuang.java_primary.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* 主要使用for迴圈和迭代器
*
* Created by 框 on 2018/6/19.
*/
public class ListTraverse {
public static void main(String[] args) {
List<Integer> list = new ArrayList();
list.add(6);
list.add(12);
list.add(4);
list.add(2);
list.add(3);
list.add(5);
//1. for迴圈遍歷
for(Iterator iterator = list.iterator(); iterator.hasNext();){
int i = (Integer) iterator.next();
System.out.println(i);
}
System.out.println(".......................");
//2. 迭代器
Iterator<Integer> it = list.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
System.out.println(".......................");
//3. 增強for迴圈
for (int i : list) {
System.out.println(i);
}
}
}