Java中Collection和Map體系(Java容器)

Java中Collection和Map體系(Java容器)

Java常用容器類繼承關係圖解

Java Iterable集合體系常用類關係圖.png

Java Map體系常用類關係圖.png

Java容器類簡介

Java中容器類主要分爲四中體系:ListSetQueueMap

List:代表有序、可重複的集合;
Set:代表無序、不可重複的集合;
Queue:代表一種隊列集合實現;
Map:代表具有映射關係的集合。

容器簡介

Collection:Collection體系中的基本接口,沒有直接實現類,只有子接口(包含ListSetQueue接口等);定義了對集合的基本操作方法(增、刪、改、查、遍歷、獲取集合大小等);
List:是一個有序的 Collection,使用此接口能夠精確的控制每個元素插入的位置,能夠通過索引(元素在List中位置,類似於數組的下標)來訪問List中的元素,第一個元素的索引爲 0,而且允許有相同的元素;List 接口存儲一組不唯一,有序(插入順序)的對象。
Set:Set集合與Collection集合基本相同,沒有提供其他額外的方法。實際上Set就是Collection,只是行爲略有不同;Set 接口存儲一組唯一,無序的對象。
Queue:Queue表示隊列這種數據結構,隊列通常是指**“先進先出”(FIFO,first-in-first-out)的容器**。新元素插入(offer)到隊列的尾部,訪問元素(poll)操作會返回隊列頭部的元素。通常,隊列不允許隨機訪問隊列中的元素。
Stack:Stack表示棧結構。與隊列(Queue)不同,它實現了一個標準的**“後進先出”(LIFO,last-in-first-out)的容器**。
Map:Map 接口存儲一組鍵值對對象,提供key(鍵)到value(值)的映射。key和value之間存在單向一對一關係,即通過指定的key,總能找到唯一的、確定的value。從Map中取出數據時,只要給出指定的key,就可以取出對應的value,Map的key不能重複,如果重複添加,會覆蓋原來的值。

容器的元素存取與遍歷

List

存取元素

List<String> list = new ArrayList<>();

// 增加元素
list.add("BB");
list.add("CC");
list.add(0, "AA");

// 根據索引獲取值
String value = list.get(0);

遍歷

List<String> list = new ArrayList<>();

// 增加元素
list.add("AA");
list.add("BB");
list.add("CC");

// 方式1:使用foreach遍歷List,推薦
System.out.println("使用foreach遍歷List:");
for (String str : list) {            //也可以改寫for(int i=0;i<list.size();i++)這種形式
    System.out.println(str);
}

// 方式2:變爲數組相關的內容進行遍歷
System.out.println("變爲數組相關的內容進行遍歷:");
String[] strArray = new String[list.size()];
list.toArray(strArray);
for (int i = 0; i < strArray.length; i++) { //這裏也可以改寫爲  foreach(String str:strArray)這種形式
    System.out.println(strArray[i]);
}

// 方式3:使用迭代器進行相關遍歷
System.out.println("使用迭代器進行相關遍歷:");
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()) { //判斷下一個元素之後有值
    System.out.println(iterator.next());
}

Set

存取元素

Set<String> set = new HashSet<>();

// 添加元素
set.add("AA");
set.add("BB");
set.add("CC");
// set 集合沒有提供快速取出指定位置或者指定元素的方法
// 只能遍歷取值,或者將set集合轉換爲list集合,在使用list集合的方法取數據

遍歷

Set<String> set = new HashSet<>();

// 添加元素
set.add("AA");
set.add("BB");
set.add("CC");


// 方式1:使用foreach遍歷set,推薦
System.out.println("使用foreach遍歷Set:");
for (String str : set) {            // 沒有 for(int i=0;i<list.size();i++)這種形式
    System.out.println(str);
}

// 方式2:變爲數組相關的內容進行遍歷
System.out.println("把鏈表變爲數組相關的內容進行遍歷:");
String[] strArray = new String[set.size()];
set.toArray(strArray);
for (int i = 0; i < strArray.length; i++) { //這裏也可以改寫爲  foreach(String str:strArray)這種形式
    System.out.println(strArray[i]);
}

// 方式3:使用迭代器進行相關遍歷
System.out.println("使用迭代器進行相關遍歷:");
Iterator<String> iterator = set.iterator();
while (iterator.hasNext()) { //判斷下一個元素之後有值
    System.out.println(iterator.next());
}

// 方式4:變爲List集合後使用操作
List<String> list = new ArrayList<>(set);
System.out.println(list);

Map

存取元素

Map<Integer,String> map = new HashMap<>();

// 添加元素
map.put(1,"AA");
map.put(2,"BB");
map.put(3,"CC");
// 根據 key 獲取 value
String value = map.get(1);

遍歷

Map<Integer, String> map = new HashMap<>();
// 添加元素
map.put(1, "AA");
map.put(2, "BB");
map.put(3, "CC");

// 方式1
System.out.println("通過Map.keySet遍歷key和value:");
for (Integer integer : map.keySet()) {
    String value = map.get(integer);
    System.out.println("key=" + integer + "; value=" + value);
}

// 方式2,推薦
System.out.println("通過Map.entrySet遍歷key和value:");
for (Map.Entry<Integer, String> integerStringEntry : map.entrySet()) {
    System.out.println("key=" + integerStringEntry.getKey() + "; value=" + integerStringEntry.getValue());
}

// 方式3
System.out.println("通過Map.entrySet使用iterator遍歷key和value:");
Iterator<Map.Entry<Integer, String>> iterator = map.entrySet().iterator();
while (iterator.hasNext()) {
    Map.Entry<Integer, String> entry = iterator.next();
    System.out.println("key=" + entry.getKey() + "; value=" + entry.getValue());
}

// 方式4,只能遍歷value
System.out.println("通過Map.values()遍歷所有的value,但不能遍歷key:");
for (String value : map.values()) {
    System.out.println("value=" + value);
}

Queue

存取元素

 Queue<String> queue = new ArrayDeque<>();

queue.add("AA");
queue.offer("BB");
queue.offer("CC");
queue.offer("DD");

System.out.println(queue);
String element = queue.element(); // 獲取,但是不移除此隊列的頭
String peek = queue.peek(); // 獲取但不移除此隊列的頭;如果此隊列爲空,則返回 null
String remove = queue.remove(); // 獲取並移除此隊列的頭
String poll = queue.poll(); // 獲取並移除此隊列的頭,如果此隊列爲空,則返回 null

System.out.println("element: " + element + " peek: " + peek + " remove: " + remove + " poll: " + poll);
System.out.println(queue); 

遍歷元素

Queue<String> queue = new ArrayDeque<>();
queue.add("AA");
queue.offer("BB");
queue.offer("CC");
queue.offer("DD");

// 方式1:集合方式遍歷,元素不會被移除
System.out.println("集合方式遍歷,元素不會被移除: ");
for (String string : queue) {
    System.out.println(string);
}

// 方式2:隊列方式遍歷,元素逐個被移除
System.out.println("隊列方式遍歷,元素逐個被移除: ");
while (queue.peek() != null) {
    System.out.println(queue.poll());
}

Stack

存取元素

Stack<String> stringStack = new StringStack();
stringStack.add("AA");
stringStack.push("BB");
stringStack.push("CC");
stringStack.push("DD");

System.out.println(stringStack);
String peek = stringStack.peek(); // 查看堆棧頂部的對象,但不從堆棧中移除它
String pop = stringStack.pop();   // 移除堆棧頂部的對象,並作爲此函數的值返回該對象
System.out.println("peek: " + peek + " pop: " + pop);

遍歷

Stack<String> stringStack = new StringStack();
stringStack.add("AA");
stringStack.push("BB");
stringStack.push("CC");
stringStack.push("DD");

// 方式1:集合遍歷方式
System.out.println("集合遍歷方式: ");
for (String string : stringStack) {
    System.out.println(string);
}
// 方式2:棧彈出遍歷方式
System.out.println("棧彈出遍歷方式: ");
while (!stringStack.empty()){
    System.out.println(stringStack.pop());
}

線程安全/線程不安全集合

Java 中常見的線程安全的集合:
Vector:就比ArrayList多了個同步化機制(線程安全),因爲效率較低,現在已經不太建議使用
Statck:棧,繼承Vector,先進後出(LIFO)
Hashtable:就比HashMap多了個線程安全
將線程不安全的集合變爲線程安全的集合:
使用 Collections.synchronizedXxx() 方法

List<String> list = new ArrayList<>();
Set<String> set = new HashSet<>();
Map<Integer,String> map = new HashMap<>();
// 將線程不安全集合變爲線程安全集合
List<String> synchronizedList = Collections.synchronizedList(list);
Set<String> synchronizedSet = Collections.synchronizedSet(set);
Map<Integer, String> synchronizedMap = Collections.synchronizedMap(map);
// ...

使用比較器對元素自定義排序

Comparable和Comparator接口都是爲了對類進行比較,衆所周知,諸如Integer,double等基本數據類型,java可以對他們進行比較,而對於類的比較,需要人工定義比較用到的字段比較邏輯。可以把Comparable理解爲內部比較器,而Comparator是外部比較器,基本的寫法如下:

使用 Comparable 排序

// 定義實體類
public class UserA implements Comparable<UserA> {
    public String name;
    public int age;

    public UserA(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public int compareTo(UserA o) {
        return this.age - o.age;
    }

    @Override
    public String toString() {
        return "UserA{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

// 使用排序
public void comparableTest(){
    List<UserA> list = new ArrayList<>();
    list.add(new UserA("張三",23));
    list.add(new UserA("李四",22));
    list.add(new UserA("王五",25));

    System.out.println("before: " + list);
    Collections.sort(list);
    System.out.println("after: " + list);
}

使用 Comparator 排序

// 定義實體類
public class UserB{
    public String name;
    public int age;

    public UserB(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "UserA{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

// 使用排序
public void comparatorTest(){
    List<UserB> list = new ArrayList<>();
    list.add(new UserB("張三",23));
    list.add(new UserB("李四",22));
    list.add(new UserB("王五",25));

    System.out.println("before: " + list);
    Collections.sort(list, new Comparator<UserB>() {
        @Override
        public int compare(UserB o1, UserB o2) {
            return o1.age - o2.age;
        }
    });
    System.out.println("after: " + list);
}

Java集合和數組的區別

  1. 數組的長度在初始化時就已經固定,也就是說只能保存固定長度的數據。而集合的長度是可以動態變化的,所以可以保存數量不確定的數據。
  2. 數組元素即可以是基本類型,也可以是對象。集合裏只能保存對象(實際上只是保存對象的引用變量),基本數據類型的值要轉換成對應的包裝類才能放入集合類中。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章