Think in Java第四版 讀書筆記5第11章

第十一章 持有對象(主要講容器類)

概要

通常程序中我們需要一些容器來存儲對象或者對象的引用
在java中承擔這一責任的是數組和容器類
數組VS容器類
數組存在一個缺陷:長度固定不夠靈活
而容器類則沒有這個缺陷,但是容器類需要的存儲空間更大

11.1 泛型的作用

在Java SE5 之前,Java還沒引入泛型,我們可以在List中放入任意類型的對象,看起來很方便是吧,但是在取出時要進行類型判斷,如果轉換錯誤還會報類型轉換錯誤導致程序異常終止
泛型的優點
1.規定了容器類的存放類型
2.將類型轉換錯誤從運行時轉移到編譯時
3.取出數據時不需要進行類型判斷和轉換了

11.2 容器的基本概念

容器的分類
1)Collection(集合類)存儲獨立元素,基本成員有List(按照順序插入) Set(不能有相同元素) Queue(先進先出 FIFO)
2)Map 存儲鍵值對 有點類似字典前面的索引與後面的具體內容的關係

容器類變量的創建:使用接口聲明變量(Effective Java 2nd 52條)
此處唯一不可以這樣用的情況是我們要使用的方法是具體類特有方法的時候

集合類添加元素與遍歷的例子

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;

public class SimpleCollection {

	public static void main(String[] args) {
		Collection<Integer> collection = new HashSet<Integer>();//Collection 是List Set Queue的父類,因此這裏可以通用 這就體現了使用接口聲明的效果了
		for (int i = 0; i < 10; i++) {
			collection.add(i);
		}
		for (Integer integer : collection) {
			System.out.println(integer + " ");
		}
	}

}

11.3 添加一組元素

添加一組元素的幾種方法的例子

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

public class AddingGroups {
	public static void printCollection(Collection<Integer> collection) {
		System.out.println(collection);
	}
	
	
	public static void main(String[] args) {
		Collection<Integer> collection = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));
		printCollection(collection);//[1, 2, 3, 4, 5] 創建時傳入一組數據
		
		Collection<Integer> collection2 = new ArrayList<Integer>(collection);
		printCollection(collection2);//[1, 2, 3, 4, 5] 創建時傳入另一個Collection對象
		
		Integer [] moreInts = {6,7,8,9,10};
		collection.addAll(Arrays.asList(moreInts));//添加一組元素方式1 調用Collection.addAll(Collection<? extends E> c)
		printCollection(collection);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
		
		//添加一組元素方式2 調用Collections.addAll(Collection<? super T> c, T... elements)
		//這樣添加元素,運行速度明顯快一些 但是無法使用這種方式進行構造(創建)Collection對象
		Collections.addAll(collection, 11,12,13,14,15);///可變參數的運用 //[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
		printCollection(collection);
		
		
		Collections.addAll(collection, moreInts);//[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 6, 7, 8, 9, 10]
		printCollection(collection);
		
		List<Integer> list = Arrays.asList(16,1,7,18,19);//Arrays.asList返回的是個定長數組 因此對它進行add delete操作都會報錯UnsupportedOperationException
		printCollection(list);//[16, 1, 7, 18, 19]
		list.set(1, 99);
		printCollection(list);//[16, 99, 7, 18, 19]
		//list.add(21);//java.lang.UnsupportedOperationException
	}
}

Arrays.asList的侷限性除了生成的List無法修改之外 在生成的類型上也可能出錯 需要指定

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

class Snow{}
class Power extends Snow{}
class Light extends Power{}
class Heavy extends Power{}
class Crusty extends Snow{}
class Slush extends Snow{}

public class AsListInterface {

	public static void main(String[] args) {
		List<Snow> snow1 = Arrays.asList(new Crusty(),new Slush(),new Power());
		
		//List<Snow> snow2 = Arrays.asList(new Light(),new Heavy());
		//編譯不通過 List<Snow>期望值爲List<Power>
		
		List<Snow> snows3 = new ArrayList<Snow>();
		Collections.addAll(snows3, new Light(),new Heavy());//Collections.addAll不會有上面的問題
		
		//以下的寫法可以 因爲Arrays.<Snow>中告訴編譯器對於Arrays.asList應該產生的List類型 這稱爲顯示類型參數說明
		List<Snow> snow4 = Arrays.<Snow>asList(new Light(),new Heavy(),new Snow());
	}

}

另外注意區分Collection(接口)和Collections(工具類,專門提供排序遍歷查找比較等方法 和Arrays類似,很好記,Collections和Arrays都是工具類,都帶s)

容器的打印

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;
import java.util.TreeSet;
//Java 中兩種容器:Collection和Map 的簡單介紹
//Collection每個“槽”只能保存一個元素 Collection包括List Set元素不能重複 Queue FIFO
//Map每個“槽”可以保存兩個元素:鍵和值
public class PrintingContainers {
	static Collection<String> fill(Collection<String> collection) {
		collection.add("rat");
		collection.add("cat");
		collection.add("dog");
		collection.add("dog");
		return collection;
	}

	static Map<String, String> fill(Map<String, String> map) {
		map.put("rat", "1");
		map.put("cat", "2");
		map.put("dog", "3");
		map.put("dog", "4");
		return map;
	}

	public static void main(String[] args) {
		//各輸出源自AbstractMap AbstractCollection對應的toString方法
		//ArrayList LinkedList輸出一樣 但是LinkedLis包含的操作多於ArrayList
		System.out.println(fill(new ArrayList<String>()));
		System.out.println(fill(new LinkedList<String>()));
		
		//以下三種屬於Set類型 相同的數據只能保存一次
		//通常使用set時不關注存儲順序 需要關注順序的話用 TreeSet和LinkedHashSet
		System.out.println(fill(new HashSet<String>()));
		System.out.println(fill(new TreeSet<String>()));
		System.out.println(fill(new LinkedHashSet<String>()));
		
		//三種map 特點是存儲鍵值對 Map有很多特別的特性
		//對於其原理可以參考我之前的一篇文章 https://blog.csdn.net/u011109881/article/details/80379505
		System.out.println(fill(new HashMap<String, String>()));
		System.out.println(fill(new TreeMap<String, String>()));
		System.out.println(fill(new LinkedHashMap<String, String>()));
	}
}
/*
out put:
[rat, cat, dog, dog]
[rat, cat, dog, dog]
[rat, cat, dog]
[cat, dog, rat]
[rat, cat, dog]
{rat=1, cat=2, dog=4}
{cat=2, dog=4, rat=1}
{rat=1, cat=2, dog=4}
*/

11.5 List

List有兩種經常使用的類型
ArrayList 擅長隨機訪問
LinkedList 擅長從中間插入元素
書中例子沒有列出完整代碼,這裏就不寫代碼 代碼無非演示了List
List有這些方法,可以直接在api看到詳細介紹
在這裏插入圖片描述

1.6 迭代器

迭代器的存在方便了我們對集合類的訪問
迭代器還可以進行一些元素的操作
迭代器的存在 將容器的訪問與容器的底層結構相分離,我們不需要知道底層的具體存儲類型就可以訪問。
不過迭代器丟失了當前訪問item的索引,如果想要索引 還是得使用傳統的for循環來遍歷

11.6.1 ListIterator

最大特點是可以指定cursor的index

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;

//簡單介紹ListIterator的例子(只能遍歷List 無法用在set上)
public class ListIteration {

	public static void main(String[] args) {
		List<String> strings = new ArrayList<String>();
		strings.add("0");
		strings.add("1");
		strings.add("2");
		strings.add("3");
		strings.add("4");
		strings.add("5");
		strings.add("6");
		strings.add("7");
		ListIterator<String> it = strings.listIterator();
		while (it.hasNext()) {
			//獲取前後索引index
			System.out.println(it.next()+","+it.nextIndex()+","+it.previousIndex());//注意next方法執行後cursor已經後移
			//同樣it.previous也會導致cursor前移
		}
		System.out.println();
		while (it.hasPrevious()) {
			System.out.print(it.previous()+" ");//向前倒序訪問
		}
		System.out.println();
		System.out.println(strings);//打印原始字符串
		it = strings.listIterator(3);//獲取index爲3的Iterator
		while (it.hasNext()) {
			String string = it.next();
			System.out.print(string+" ");
			it.set(""+(Integer.valueOf(string)+1));//set方法替換訪問的最後一個元素
		}
		System.out.println();
		System.out.println(strings);
	}
}
/** out put
0,1,0
1,2,1
2,3,2
3,4,3
4,5,4
5,6,5
6,7,6
7,8,7

7 6 5 4 3 2 1 0 
[0, 1, 2, 3, 4, 5, 6, 7]
3 4 5 6 7 
[0, 1, 2, 4, 5, 6, 7, 8]
*/

11.7 LinkedList

import java.util.Arrays;
import java.util.LinkedList;

public class LinkedListFeatures {

	public static void main(String[] args) {
		LinkedList<String> strings = new LinkedList<String>(Arrays.asList("0","1","2","3","4","5","6","7","8"));
		System.out.println(strings);
		System.out.println(strings.getFirst());//取出頭部(第一個)元素 但是不從List中刪除 比下面兩個方法多了null list時拋出NoSuchElementException的邏輯
		System.out.println(strings.element());//取出頭部(第一個)元素 但是不從List中刪除 element內部調用的getFirst方法
		System.out.println(strings.peek());//取出頭部(第一個)元素 但是不從List中刪除
		System.out.println(strings);
		System.out.println("------------");
		System.out.println(strings.remove());//取出頭部(第一個)元素 並且從List中刪除 內部調用的removeFirst
		System.out.println(strings.removeFirst());//取出頭部(第一個)元素 並且從List中刪除
		System.out.println(strings.poll());//取出頭部(第一個)元素 並且從List中刪除 和removeFirst的區別在於判空
//	    public E removeFirst() {
//	        final Node<E> f = first;
//	        if (f == null)
//	            throw new NoSuchElementException();
//	        return unlinkFirst(f);
//	    }
		
//	    public E poll() {
//	        final Node<E> f = first;
//	        return (f == null) ? null : unlinkFirst(f);
//	    }
		System.out.println(strings);
		System.out.println("----------------");
		strings.addFirst("addFirst");//在頭部加數據
		strings.offer("offer");//在尾部加數據 內部調用add方法
		strings.add("add");//在尾部加數據
		strings.addLast("addLast");//在尾部加數據 和add方法實現 不過add方法有返回值
		System.out.println(strings);
		strings.removeLast();//從尾部刪除
		System.out.println(strings);
		strings.remove(1);//刪除指定下標
		System.out.println(strings);
	}
}
/** output
[0, 1, 2, 3, 4, 5, 6, 7, 8]
0
0
0
[0, 1, 2, 3, 4, 5, 6, 7, 8]
------------
0
1
2
[3, 4, 5, 6, 7, 8]
----------------
[addFirst, 3, 4, 5, 6, 7, 8, offer, add, addLast]
[addFirst, 3, 4, 5, 6, 7, 8, offer, add]
[addFirst, 4, 5, 6, 7, 8, offer, add]

 */

LinkedList本身可以模擬Queue

11.8 Stack

import java.util.HashSet;
import java.util.Random;
import java.util.Set;
//Set不保存重複元素
//Set常用方法是查看某個元素是否在集合中
//因此查找是set的常用操作
//hashSet對查找進行了優化

//Set 繼承自Collection接口並且沒有添加新方法,因此Set的方法和Collection的方法完全一致
//但是Set的行爲卻不同 這就像Java的多態一樣--表現不同的行爲
public class SetOfInteger {

	public static void main(String[] args) {
		Random random = new Random(47);
		Set<Integer> integers = new HashSet<Integer>();//HashSet TreeSet都是順序的 LinkedHashSet是亂序的
		//HashSet的輸出結果書中的結論不一致 可能是因爲在新版本Java中修改了hashSet的實現,此處不明確 如有錯誤請幫忙指出
		for (int i = 0; i < 10000; i++) {
			integers.add(random.nextInt(30));
			//調用add實際調用了10000次 但是隻有30次成功了,其他失敗
			//是因爲add的數值已經存在
		}
		System.out.println(integers);
	}

}
//輸出:
//[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

//測試Set的包含關係
public class SetOperations {

	public static void main(String[] args) {
		Set<String> set1 = new HashSet<String>();
		Collections.addAll(set1, "A B C D E F G H I J K L".split(" "));
		set1.add("M");
		System.out.println("H in set1 " + set1.contains("H"));
		System.out.println("N in set1 " + set1.contains("N"));

		Set<String> set2 = new HashSet<String>();
		Collections.addAll(set1, "H I J K L".split(" "));
		System.out.println("set2 in set1 " + set1.containsAll(set2));
		set1.remove("H");
		System.out.println("set1 " + set1);
		System.out.println("set2 in set1 " + set1.containsAll(set2));
		set1.removeAll(set2);
		System.out.println("after removeAll in set2" + set1);
		Collections.addAll(set1, "X Y Z".split(" "));
		System.out.println("XYZ add to set1 " + set1);
	}

}
/**
H in set1 true
N in set1 false
set2 in set1 true
set1 [A, B, C, D, E, F, G, I, J, K, L, M]
set2 in set1 true
after removeAll in set2[A, B, C, D, E, F, G, I, J, K, L, M]
XYZ add to set1 [A, B, C, D, E, F, G, I, J, K, L, M, X, Y, Z]
 */

書中下面的幾個例子用到了Compare和書裏提供的工具類,就略過了。

11.10 MAP

map是經常使用的數據存儲工具,比如產生10000個[0,20)的隨機數,map就是很好的選擇,可以以[0,20)的數字爲鍵,出現的次數爲值,程序也很簡單,就不列出了。
Map還有containsKey和containsValue方法來判斷map是否包含指定的鍵或值
Map的值存儲的東西可以是基本類型 也可以是其他對象,比如List Map等等,比如我們想要存儲一些有多個寵物的人,那麼我們可以用Map<Person,List< Pet >>來存儲。
Map也可以返回它的鍵集合或者值集合,即keySet和values方法
Map是一個非常重要的存儲工具

11.11 Queue

Queue是一種FIFO先進先出的容器,比如排隊買票,自然是先排隊的人先買到票然後退出隊伍,還是很形象的。

import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;

//利用LinkedList模擬構建Queue,之所以可以模擬(通過向下轉型),原因如下
//public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable
//public interface Deque<E> extends Queue<E> 
//因此LinkedList間接實現了Queue 它滿足Queue的所有行爲
public class QueueDemo {
	public static void printQ(Queue queue) {
		while (queue.peek() != null) {
			System.out.print(queue.remove() + " ");// 從頭部刪除(取出)
		}
		System.out.println("|||||");
	}

	public static void main(String[] args) {
		Queue<Integer> queue = new LinkedList<Integer>();
		Random random = new Random(47);
		for (int i = 0; i < 10; i++) {
			queue.offer(random.nextInt(i + 10));// 從尾部添加
		}
		printQ(queue);
		Queue<Character> qc = new LinkedList<Character>();
		for (char c : "China".toCharArray()) {
			qc.offer(c);
		}
		printQ(qc);
	}

}

11.11.1 PriorityQueue

public class PriorityQueueDemo {

	public static void main(String[] args) {
		//PriorityQueue 優先級隊列並不完全遵照FIFO的原則,它的元素還有一個權重(優先級)
		//例子1 PriorityQueue存放整型
		PriorityQueue<Integer> priorityQueue = new PriorityQueue<Integer>();
		Random random = new Random(47);
		for (int i = 0; i < 10; i++) {
			priorityQueue.offer(random.nextInt(i+10));
		}
		QueueDemo.printQ(priorityQueue);
		
		//例子2 PriorityQueue存放整型
		List<Integer> ints = Arrays.asList(25,22,20,18,14,9,3,1,1,2,3,9,14,18,21,23,25);
		priorityQueue = new PriorityQueue<Integer>(ints);
		QueueDemo.printQ(priorityQueue);
		
		//例子3 PriorityQueue存放反序整型 第二個參數是Comparator 決定了元素的權重
		priorityQueue = new PriorityQueue<Integer>(ints.size(),Collections.reverseOrder());
		priorityQueue.addAll(ints);
		QueueDemo.printQ(priorityQueue);
		
		//例子4 PriorityQueue存放word 默認按照字典順序分配權重
		String fact = "EDUCATION SHOULD ESCHEW OBFUSCATION";
		List<String> strings = Arrays.asList(fact.split(" "));
		PriorityQueue<String> stringPQ = new PriorityQueue<String>(strings);
		QueueDemo.printQ(stringPQ);
		
		//例子5 PriorityQueue存放word 默認按照字典反序分配權重
		stringPQ = new PriorityQueue<String>(strings.size(),Collections.reverseOrder());
		stringPQ.addAll(strings);
		QueueDemo.printQ(stringPQ);
		
		//例子6 PriorityQueue存放字符 改成Set存儲 所以沒有重複值
		Set<Character> charSet = new HashSet<Character>();
		for (char c : fact.toCharArray()) {
			charSet.add(c);
		}
		PriorityQueue<Character> characterPQ = new PriorityQueue<Character>(charSet);
		QueueDemo.printQ(characterPQ);
	}

}
/**
 * 輸出:
0 1 1 1 1 1 3 5 8 14 |||||
1 1 2 3 3 9 9 14 14 18 18 20 21 22 23 25 25 |||||
25 25 23 22 21 20 18 18 14 14 9 9 3 3 2 1 1 |||||
EDUCATION ESCHEW OBFUSCATION SHOULD |||||
SHOULD OBFUSCATION ESCHEW EDUCATION |||||
  A B C D E F H I L N O S T U W |||||
 */

11.12 Collection 和 Iterator

public class InterfaceVSIterator {
	public static void display(Iterator<String> it){
		while (it.hasNext()) {
			System.out.print(it.next()+" ");
		}
		System.out.println();
	}
	
	public static void display(Collection<String> collection) {
		for(String string:collection){
			System.out.print(string+" ");
		}
		System.out.println();
	}

	public static void main(String[] args) {
		List<String> strings = Arrays.asList("My","Name","Is","AAA","Nice","To","Meet","You");//順序存儲
		Set<String> stringSet = new HashSet<String>(strings);//不存儲相同字符 存儲順序按照散列順序存儲
		Map<String, String> stringMap = new LinkedHashMap<String, String>();
		String [] namesStrings = ("A,B,C,D,E,F,G,H").split(",");
		for (int i = 0; i < namesStrings.length; i++) {
			stringMap.put(namesStrings[i], strings.get(i));
		}
		
		display(strings);
		display(stringSet);
		
		display(strings.iterator());
		display(stringSet.iterator());
		
		System.out.println(stringMap);
		System.out.println(stringMap.keySet());
		
		display(stringMap.values());
		display(stringMap.values().iterator());
	}

}
/** 輸出:(看起來iterator和collection沒有區別)
My Name Is AAA Nice To Meet You 
AAA Meet Nice Is To My You Name 
My Name Is AAA Nice To Meet You 
AAA Meet Nice Is To My You Name 
{A=My, B=Name, C=Is, D=AAA, E=Nice, F=To, G=Meet, H=You}
[A, B, C, D, E, F, G, H]
My Name Is AAA Nice To Meet You 
My Name Is AAA Nice To Meet You 
 */

本例看起來collection 和 iterator功能基本一樣,只不過一個利用foreach來遍歷一個用next遍歷,但是我們需要注意public interface Collection extends Iterable的類結構,因此iterator有時候比collection更輕便。

11.3 foreach 與迭代器(Iterator)

foreach不僅僅可以使用在list上 事實上只要實現了Iterable接口 就可以使用foreach進行遍歷,比如collection
例子:實現自己的Iterable

import java.util.Iterator;
/**
 * 
 * Iterable和Iterator
 * 
 * Iterable(實現Iterable接口允許該對象使用for-each語法)
 * Implementing this interface allows an object to be the target of
 * the "for-each loop" statement.
 * 
 * Iterator
 * Iterator取代了原先的Java集合框架中的枚舉,Iterator和枚舉有兩點不同
 * 1.Iterator在完善的語義語法定義下可以在遍歷時刪除元素
 * 2.方法名改進
 * Iterator是Java集合類的一個成員
 * An iterator over a collection. Iterator takes the place of ink Enumeration in the Java Collections Framework.  Iterators differ from enumerations in two ways:
 * 1.Iterators allow the caller to remove elements from the underlying collection during the iteration with well-defined semantics.
 * 2.Method names have been improved.
 * This interface is a member of the Java Collections Framework
 */

public class IterableClass implements Iterable<String> {
	IterableClass(){
		
	}
	protected String[] words = ("And that is how we know the Earth to be banana-shaped")
			.split(" ");

	public Iterator<String> iterator() {
		return new Iterator<String>() {
			private int index = 0;

			public boolean hasNext() {
				return index < words.length;
			}

			public String next() {
				return words[index++];
			}

			public void remove() {
				throw new UnsupportedOperationException("remove");
			}

		};
	}
	
	public static void main(String[] args) {
		for (String s: new IterableClass()) {
			System.out.print(s+" ");
		}
	}

}

通常自定義Iterable類時先實現Iterable,然後覆寫Iterable中的iterator方法,其返回值是Iterator對象,上面的例子即是匿名內部類的使用
注意數組不是Iterable的

public class ArrayIsNotIterable {
	static <T> void test(Iterable<T> ib){
		for (T t :ib) {
			System.out.print(t+" ");
		}
	}
	
	public static void main(String [] args){
		test(Arrays.asList(1,2,3));
		String [] strings = {"A","B","C"};
		//test(strings); 編譯不過 說明數組不是Iterable的
		//Arrays.asList將數組轉換成list 而list是Iterable的 此時可以進行遍歷
		test(Arrays.asList(strings));
	}

}

11.13.1 適配器模式與Iterator的結合
假設現在我們要進行一個單詞表的正向或者方向遍歷,Iterable接口的方法iterator只提供了一種遍歷方式,如何實現這種需求呢?就要用到適配器了。

public class ReversibleArrayList<T> extends ArrayList<T> {
	public ReversibleArrayList(Collection<T> c) {
		super(c);// 沿用父類的構造方法
	}

	public Iterable<T> reversed() {//由於for-each使用的是Iterable對象,我們可以使用新的Iterable來實現新的輸出
		//對於for each 使用返回不同的Iterable方法 ,個人決定這個更像策略模式?
		return new Iterable<T>() {
			public Iterator<T> iterator() {
				return new Iterator<T>() {
					int current = size() - 1;

					public boolean hasNext() {
						return current > -1;
					}

					public T next() {
						return get(current--);// 先返回對象 之後index--
					}

				};
			}
		};
	}
}
public class AdapterMethodIdiom {

	public static void main(String[] args) {
		//給for-each 傳入不同的iterator對象則輸出不同
		
		ReversibleArrayList<String> ral = new ReversibleArrayList<String>(Arrays.asList("To be or not to be ?".split(" ")));
		for (String string : ral) {//順序輸出
			System.out.print(string+" ");
		}
		System.out.println();
		
		for (String string : ral.reversed()) {//反序輸出
			System.out.print(string+" ");
		}
		
	}
}
//備註Collections.shuffle(ral,new Random(47)); 是一個隨機打亂List的方法

總結

1.數組長度不可變
2.collection存放單一元素 map存放鍵值對,collection和map都能自動調整size
3.Array list隨機訪問效率高 LinkedList進行元素插入效率高
4.LinkedList可以模擬stack和Queue
5.HashMap被設計進行快速訪問,TreeMap的鍵需要保持有序,因此沒有HashMap快,LinkedhashMap兼具有序和快速訪問
6.Set存放非重複元素,HashSet訪問速度很快 TreeSet有序 LinkedHashSet以插入順序存放元素
7.常用集合類和接口
在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章