集合概述
- 概念:對象的容器,定義了對多個對象進項操作的的常用方法。可實作數組的功能。
- 和數組的差別:
- 數組長度固定,集合長度不固定。
- 數組可以存儲基本類型和引用類型,集合隻能存儲引用類型。
- 位置: java.util.*;
Collection體系集合
Collection父接口
- 特點:代表一組任意類型的對象,無序、無下标、不能重複。
- 方法:
-
boolean add(Object obj) //添加一個對象。
-
boolean addAll(Collection c) //講一個集合中的所有對象添加到此集合中。
-
void clear() //清空此集合中的所有對象。
-
boolean contains(Object o) //檢查此集合中是否包含o對象。
-
boolean equals(Object o) //比較此集合是否與指定對象相等。
-
boolean isEmpty() //判斷此集合是否為空。
-
boolean remove(Object o) //在此集合中移除o對象。
-
int size() //傳回此集合中的元素個數。
-
Object[] toArray() //姜此集合轉換成數組。
-
1 /**
2 * Collection接口的使用(一)
3 * 1.添加元素
4 * 2.删除元素
5 * 3.周遊元素
6 * 4.判斷
7 */
8 public class Demo01 {
9 public static void main(String[] args) {
10 //建立集合
11 Collection collection = new ArrayList();
12
13 // * 1.添加元素
14 collection.add("西瓜");
15 collection.add("蘋果");
16 collection.add("榴蓮");
17 System.out.println(collection.size());
18 System.out.println(collection.toString());
19
20 // * 2.删除元素
21 collection.remove("西瓜");
22 System.out.println("删除之後:"+collection.size());
23
24 // * 3.周遊元素
25 //3.1 使用增強for
26 for (Object object:collection) {
27 String s = (String) object;
28 System.out.println(s);
29 }
30 //3.2 使用疊代器(疊代器專門用來周遊集合的一種方式)
31 //hasnext();判斷是否有下一個元素
32 //next();擷取下一個元素
33 //remove();删除目前元素
34 Iterator it = collection.iterator();
35 while (it.hasNext()){
36 String s = (String) it.next();
37 System.out.println(s);
38 //删除操作
39 //collection.remove(s);引發錯誤:并發修改異常
40 //iterator.remove();應使用疊代器的方法
41
42 // * 4.判斷
43 System.out.println(collection.contains("蘋果"));//true 是否存在蘋果
44 System.out.println(collection.isEmpty());//false 是否有資料,沒有資料為true,有資料為false
45 }
46 }
47 }
1 /**
2 * Collection接口的使用(二)
3 * 1.添加元素
4 * 2.删除元素
5 * 3.周遊元素
6 * 4.判斷
7 */
8 public class Demo02 {
9 public static void main(String[] args) {
10
11 //建立Collection對象
12 Collection collection = new ArrayList();
13
14 //建立Student對象
15 Student s1 = new Student("張三",18);
16 Student s2 = new Student("李四",19);
17 Student s3 = new Student("王五",20);
18
19 //1.添加資料
20 collection.add(s1);
21 collection.add(s2);
22 collection.add(s3);
23 //collection.add(s3);可重複添加相同對象
24 System.out.println("元素個數為:"+collection.size());
25 System.out.println(collection.toString());
26
27 //2.删除資料
28 collection.remove(s1);
29 System.out.println("元素個數為:"+collection.size());
30 System.out.println(collection.toString());
31
32 //3.周遊資料
33 //3.1 增強for循環
34 for (Object object:collection) {
35 Student s = (Student) object;
36 System.out.println(object);
37 }
38
39 //3.2 疊代資料
40 //疊代過程中不能使用Collection的删除方法,即Collection.remove()
41 Iterator it = collection.iterator();
42 while (it.hasNext()){
43 Student s = (Student) it.next();
44 System.out.println(s);
45 //删除
46 //it.remove();
47 }
48
49 //4判斷
50 System.out.println(collection.contains("張三"));//false
51 System.out.println(collection.contains(s2));//true
52 System.out.println(collection.isEmpty());//false
53 }
54 }
1 /**
2 * 學生類
3 */
4 public class Student {
5 private String name;
6 private int age;
7
8 //有參構造
9 public Student(String name, int age) {
10 this.name = name;
11 this.age = age;
12 }
13
14 //無參構造
15 public Student() {
16 }
17
18 //重寫toString
19 @Override
20 public String toString() {
21 return "Student{" +
22 "name='" + name + '\'' +
23 ", age=" + age +
24 '}';
25 }
26
27 //get/set靜态屬性
28 public String getName() {
29 return name;
30 }
31
32 public void setName(String name) {
33 this.name = name;
34 }
35
36 public int getAge() {
37 return age;
38 }
39
40 public void setAge(int age) {
41 this.age = age;
42 }
43 }
Collection子接口
List集合
- 特點:有序、有下标、元素可以重複。
-
-
void add(int index,Object o) //在index位置插入對象o。
-
boolean addAll(index,Collection c) //将一個集合中的元素添加到此集合中的index位置。
-
Object get(int index) //傳回集合中指定位置的元素。
-
List subList(int fromIndex,int toIndex) //傳回fromIndex和toIndex之間的集合元素。
-
1 /**
2 * List子接口的使用(一)
3 * 特點:1.有序有下标 2.可以重複
4 *
5 * 1.添加元素
6 * 2.删除元素
7 * 3.周遊元素
8 * 4.判斷
9 * 5.擷取位置
10 */
11 public class Demo03 {
12 public static void main(String[] args) {
13
14 //1.建立list集合對象
15 List list = new ArrayList<>();
16
17 //2.添加元素
18 list.add("迪迦");
19 list.add("艾斯");
20 list.add(0,"賽文");//根據index下标插入資料
21 System.out.println("元素個數為:"+list.size());
22 System.out.println(list.toString());
23
24 //3.删除資料
25 list.remove(1);
26 //list.remove("迪迦");意思同上,一個是根據角标,一個是根據内容
27 System.out.println("删除之後:"+list.size());
28 System.out.println(list.toString());
29
30 //4.周遊元素
31 //4.1 因為有下标,是以可以使用for循環
32 for (int i = 0; i < list.size(); i++) {
33 System.out.println(list.get(i));
34 }
35 //4.2 使用增強for循環
36 for (Object object:list) {
37 String s = (String) object;
38 System.out.println(s);
39 }
40 //4.3 使用疊代器
41 Iterator it = list.iterator();
42 while (it.hasNext()){
43 String s = (String) it.next();
44 System.out.println(s);
45 }
46 //4.4 使用清單疊代器
47 ListIterator listIterator = list.listIterator();
48 //從前往後周遊
49 while (listIterator.hasNext()){
50 String s = (String) listIterator.next();
51 System.out.println(s);
52 }
53 //從後往前周遊(此時“周遊指針”已經指向末尾了)
54 while (listIterator.hasPrevious()){
55 String s = (String) listIterator.previous();
56 System.out.println(s);
57 }
58
59 //5.判斷
60 System.out.println(list.contains("賽文"));//true
61 System.out.println(list.isEmpty());//false
62
63 //6.擷取位置
64 System.out.println(list.indexOf("艾斯"));//1
65 }
66 }
1 /**
2 * List子接口的使用(二)
3 * 1.添加元素
4 * 2.删除元素
5 * 3.周遊元素
6 * 4.判斷
7 * 5.擷取位置
8 */
9 public class Demo04 {
10 public static void main(String[] args) {
11 List list = new ArrayList<>();
12 //1.添加基本類型數字資料(自動裝箱)
13 list.add(10);
14 list.add(20);
15 list.add(30);
16 list.add(40);
17 list.add(40);
18 System.out.println("元素個數為:"+list.size());
19 System.out.println(list.toString());
20
21 //2.删除資料
22 list.remove(0);//根據下标删除
23 //list.remove(40);下标越界
24 list.remove(new Integer(40));//根據内容删除,将基本類型轉成引用類型
25 System.out.println("删除後:"+list.size());
26 System.out.println(list.toString());
27
28 //3.周遊元素
29 //3.1 使用for循環
30 for (int i = 0; i < list.size(); i++) {
31 System.out.println(list.get(i));
32 }
33 //3.2 使用增強for循環
34 for (Object object:list) {
35 int s = (int) object;
36 System.out.println(s);
37 }
38 //3.3 使用疊代器
39 Iterator it = list.iterator();
40 while (it.hasNext()){
41 int s = (int) it.next();
42 System.out.println(s);
43 }
44 //3.4 使用清單疊代器
45 ListIterator listIterator = list.listIterator();
46 //從前往後周遊
47 while (listIterator.hasNext()){
48 int s = (int) listIterator.next();
49 System.out.println(s);
50 }
51 //從後往前周遊(此時“周遊指針”已經指向末尾了)
52 while (listIterator.hasPrevious()){
53 int s = (int) listIterator.previous();
54 System.out.println(s);
55 }
56
57 //4.判斷
58 System.out.println(list.contains(20));//true
59 System.out.println(list.isEmpty());//false
60
61 //5.擷取位置
62 System.out.println(list.indexOf(30));//1
63
64 //6.補充方法sublist,根據角标範圍,傳回集合元素,含頭不含尾
65 List list1 = list.subList(0,2);
66 System.out.println(list1.toString());//20,30
67 }
68 }
List實作類
ArrayList【重點】
- 數組結構實作,查詢快、增删慢;
- JDK1.2版本,運作效率快、線程不安全。
1 /**
2 * ArrayList的使用
3 * 存儲結構:數組;
4 * 特點:查找周遊速度快,增删慢。
5 * 1.添加元素
6 * 2.删除元素
7 * 3.周遊元素
8 * 4.判斷
9 * 5.查找
10 */
11 public class Demo05 {
12 public static void main(String[] args) {
13 ArrayList arrayList = new ArrayList<>();
14 //1.添加元素
15 Student s1 = new Student("鋼鐵俠",3);
16 Student s2 = new Student("蜘蛛俠",4);
17 Student s3 = new Student("蝙蝠俠",5);
18 arrayList.add(s1);
19 arrayList.add(s2);
20 arrayList.add(s3);
21 arrayList.add(s3);
22 System.out.println("元素個數:"+arrayList.size());
23 System.out.println(arrayList.toString());
24
25 //2.删除元素
26 arrayList.remove(s3);
27 System.out.println("删除後:"+arrayList.size());
28 System.out.println(arrayList.toString());
29 //arrayList.remove(new Student("唐", 21));
30 //注:這樣可以删除嗎(不可以)?顯然這是兩個不同的對象。
31 //假如兩個對象屬性相同便認為其是同一對象,那麼如何修改代碼?
32
33 //3.周遊元素
34 //3.1使用疊代器
35 Iterator it = arrayList.iterator();
36 while (it.hasNext()){
37 Student s = (Student) it.next();
38 System.out.println(s);
39 }
40 //3.2使用清單疊代器
41 ListIterator listIterator = arrayList.listIterator();
42 //從前往後周遊
43 while (listIterator.hasNext()){
44 Student s = (Student) listIterator.next();
45 System.out.println(s);
46 }
47 //從後往前周遊
48 while (listIterator.hasPrevious()){
49 Student s = (Student) listIterator.previous();
50 System.out.println(s);
51 }
52
53 //4.判斷
54 System.out.println(arrayList.isEmpty());//false
55 //System.out.println(arrayList.contains(new Student("鋼鐵俠", 3)));
56 //注:與上文相同的問題。
57
58 //5.查找
59 System.out.println(arrayList.indexOf(s1));
60 }
61 }
注:Object裡的equals(this==obj)用位址和目前對象比較,如果想實作代碼中的問題,可以在學生類中重寫equals方法:
1 //重寫equls方法
2 @Override
3 public boolean equals(Object obj) {
4 //1.是否為同一對象
5 if (this == obj){
6 return true;
7 }
8 //2.判斷是否為空
9 if (obj == null){
10 return false;
11 }
12 //3.判斷是否是Student類型
13 if (this instanceof Student){
14 Student s = (Student) obj;
15 //4.比較屬性
16 if (this.name.equals(s.getName())&&this.age==s.age){
17 return true;
18 }
19 }
20 return false;
21 }
ArrayList源碼分析:
- 預設容量大小:
private static final int DEFAULT_CAPACITY = 10;
- 存放元素的數組:
transient Object[] elementData;
- 實際元素個數:
private int size;
- 建立對象時調用的無參構造函數:
1 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
2 //Arraylist無參構造方法
3 public ArrayList() {
4 this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
5 }
這段源碼說明當你沒有向集合中添加任何元素時,集合容量為0。那麼預設的10個容量怎麼來的呢?這就得看看add方法的源碼了:
1 public boolean add(E e) {
2 ensureCapacityInternal(size + 1); // Increments modCount!!
3 elementData[size++] = e;
4 return true;
5 }
假設你new了一個數組,目前容量為0,size當然也為0。這時調用add方法進入到
ensureCapacityInternal(size + 1);
該方法源碼如下:
1 private void ensureCapacityInternal(int minCapacity) {
2 if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
3 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
4 }
5
6 ensureExplicitCapacity(minCapacity);
7 }
由于一開始Arraylist的無參構造方法,就是将 DEFAULTCAPACITY_EMPTY_ELEMENTDATA 指派給了 elementData ,是以if的條件是成立的。
if語句中 minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity); 就是在 DEFAULT_CAPACITY 和 minCapacity 中傳回一個最大的參數, DEFAULT_CAPACITY 是Arrarylist中一開始就定義的靜态常量,大小為10。 minCapacity 傳入的值為size+1也就是 1
DEFAULT_CAPACITY值大,是以傳回DEFAULT_CAPACITY的值為10,
這個值作為參數又傳入
ensureExplicitCapacity()
方法中,進入該方法檢視源碼:
1 private void ensureExplicitCapacity(int minCapacity) {
2 modCount++;
3
4 // overflow-conscious code
5 if (minCapacity - elementData.length > 0)
6 grow(minCapacity);
7 }
我們先不要管modCount這個變量,可以了解為這個變量是記錄數組修改次數。
因為elementData數組長度為0,minCapacity為10,是以if條件成立,調用grow方法,重要的部分來了,這個代碼就是數組擴容的代碼,現在我們進入到grow方法的源碼中:
1 private void grow(int minCapacity) {
2 // overflow-conscious code
3 int oldCapacity = elementData.length; //oldCapactity=0
4 int newCapacity = oldCapacity + (oldCapacity >> 1); //oldCapacity=0;(oldCapacity >> 1)0右移一位還是0;是以newCapacity=0
5 if (newCapacity - minCapacity < 0) //0-10=-10,if條件成立
6 newCapacity = minCapacity; //newCapacity=10
7 if (newCapacity - MAX_ARRAY_SIZE > 0) //MAX_ARRAY_SIZE這個值大家也可以進去看下,是好幾個億,這個條件基本上永遠不會成立。可以忽略不看,了解即可
8 newCapacity = hugeCapacity(minCapacity);
9 // minCapacity is usually close to size, so this is a win:
10 elementData = Arrays.copyOf(elementData, newCapacity); //copyOf(elementData,newCapacity)建立一個新的數組elementDate,數組長度為newCapacity即就是10
11 }
這個方法先聲明了一個oldCapacity變量将數組長度賦給它,其值為0;又聲明了一個newCapacity變量其值為
oldCapacity+一個增量
,可以發現這個增量是和原數組長度有關的量,當然在這裡也為0。第一個if條件滿足,newCapacity的值為10(這就是預設的容量,不了解的話再看看前面)。第二個if條件不成立,也可以不用注意,因為MAX_ARRAY_SIZE的定義如下:
這個值太大了以至于第二個if條件沒有了解的必要。
最後一句話就是為elementData數組賦予了新的長度,
Arrays.copyOf()
方法傳回的數組是新的數組對象,原數組對象不會改變,該拷貝不會影響原來的數組。
copyOf()
的第二個自變量指定要建立的新數組長度,如果新數組的長度超過原數組的長度,則保留數組預設值。
這時候再回到add的方法中,接着就向下執行
elementData[size++] = e,将add傳入的值e指派給數組elementData,下标index為[size++]。
到這裡為止關于ArrayList就講解得差不多了,當數組長度為10的時候你們可以試着過一下源碼,查一下每次的增量是多少(答案是每次擴容為原來的1.5倍)。
Vector
- JDK1.0版本,運作效率慢、線程安全。
1 /**
2 * Vector的示範使用
3 *
4 *1.添加資料
5 *2.删除資料
6 *3.周遊
7 *4.判斷
8 */
9 public class Demo01 {
10 public static void main(String[] args) {
11 //1.建立Vector對象
12 Vector v = new Vector<>();
13
14 //2.添加資料
15 v.add("孫悟空");
16 v.add("豬八戒");
17 v.add("沙和尚");
18 System.out.println("元素個數為:"+v.size());
19 System.out.println(v.toString());
20
21 //3.删除資料
22 v.remove("沙和尚");
23 //v.remove(2);效果同上
24 System.out.println("删除後:"+v.size());
25 System.out.println(v.toString());
26
27 //4.周遊
28 //使用枚舉
29 Enumeration elements = v.elements();
30 while (elements.hasMoreElements()){
31 System.out.println(elements.nextElement());
32 }
33
34 //5.判斷
35 System.out.println(v.isEmpty());
36 System.out.println(v.contains("孫悟空"));
37 }
38 }
LinkedList
- 連結清單結構實作,增删快,查詢慢。
1 /**
2 * LinkedList的用法
3 * 存儲結構:雙向連結清單
4 * 1.建立對象
5 * 2.添加元素
6 * 3.删除元素
7 * 4.周遊
8 * 5.判斷
9 */
10 public class Demo01 {
11 public static void main(String[] args) {
12 //1.建立LinkedList對象
13 LinkedList link = new LinkedList<>();
14
15 //2.添加元素
16 Student s1 = new Student("python",1);
17 Student s2 = new Student("Java",2);
18 Student s3 = new Student("go",3);
19 link.add(s1);
20 link.add(s2);
21 link.add(s3);
22 link.add(s3);
23 System.out.println("元素個數為:"+link.size());
24 System.out.println(link.toString());
25
26 //3.删除元素
27 link.remove(s3);
28 link.remove(new Student("go",3));
29 System.out.println("删除後:"+link.size());
30 System.out.println(link.toString());
31
32 //4.周遊
33 //4.1 使用for循環周遊
34 for (int i = 0; i < link.size(); i++) {
35 System.out.println(link.get(i));
36 }
37 //4.2 使用增強for
38 for (Object object:link) {
39 Student s = (Student) object;
40 System.out.println(s.toString());
41 }
42 //4.3 使用疊代器
43 Iterator it = link.iterator();
44 while (it.hasNext()){
45 System.out.println(it.next());
46 }
47 //4.4 使用清單疊代器
48 ListIterator listIterator = link.listIterator();
49 //從前往後周遊
50 while (listIterator.hasNext()){
51 System.out.println(listIterator.next());
52 }
53 //從後往前周遊
54 while (listIterator.hasPrevious()){
55 System.out.println(listIterator.previous());
56 }
57
58 //5.判斷
59 System.out.println(link.isEmpty());
60 System.out.println(link.contains(s1));
61 System.out.println(link.contains(new Student("Java",2)));
62 }
63 }
LinkedList源碼分析
LinkedList首先有三個屬性:
- 連結清單大小:
transient int size = 0;
- (指向)第一個結點/頭結點:
transient Node<E> first;
- (指向)最後一個結點/尾結點:
transient Node<E> last;
關于Node類型我們再進入到類裡看看:
1 private static class Node<E> {
2 E item;
3 Node<E> next;
4 Node<E> prev;
5
6 Node(Node<E> prev, E element, Node<E> next) {
7 this.item = element;
8 this.next = next;
9 this.prev = prev;
10 }
11 }
首先item存放的是實際資料;next指向下一個結點而prev指向上一個結點。
Node帶參構造方法的三個參數分别是前一個結點、存儲的資料、後一個結點,調用這個構造方法時将它們指派給目前對象。
LinkedList是如何添加元素的呢?先看看add方法:
1 public boolean add(E e) {
2 linkLast(e);
3 return true;
4 }
進入到linkLast方法:
1 void linkLast(E e) {
2 final Node<E> l = last;
3 final Node<E> newNode = new Node<>(l, e, null);
4 last = newNode;
5 if (l == null)
6 first = newNode;
7 else
8 l.next = newNode;
9 size++;
10 modCount++;
11 }
假設剛開始new了一個LinkedList對象,first和last屬性都為空,調用add進入到linkLast方法。
首先建立一個Node變量 l 将last(此時為空)賦給它,然後new一個newNode變量存儲資料,并且它的前驅指向l,後繼指向null;再把last指向newNode。如下圖所示:
如果滿足if條件,說明這是添加的第一個結點,将first指向newNode:
至此,LinkedList對象的第一個資料添加完畢。假設需要再添加一個資料,我們可以再來走一遍,過程同上不再贅述,圖示如下:
ArrayList和LinkedList差別
- ArrayList:必須開辟連續空間,查詢快,增删慢。
- LinkedList:無需開辟連續空間,查詢慢,增删快。
泛型概述
- Java泛型是JDK1.5中引入的一個新特性,其本質是參數化類型,把類型作為參數傳遞。
- 常見形式有泛型類、泛型接口、泛型方法。
- 文法:
- <T,…> T稱為類型占位符,表示一種引用類型。
- 好處:
- 提高代碼的重用性。
- 防止類型轉換異常,提高代碼的安全性。
泛型類
1 /**
2 * 泛型類
3 * 文法:類名<T>
4 * T是類型占位符,表示一種引用類型,編寫多個使用逗号隔開
5 *
6 */
7 public class MyGeneric<T> {
8 //1.建立泛型變量
9 //不能使用new來建立,因為泛型是不确定的類型,也可能擁有私密的構造方法
10 T t;
11 //2.泛型作為方法的參數
12 public void show(T t){
13 System.out.println(t);
14 }
15
16 //3.泛型作為方法的傳回值
17 public T getT(){
18 return t;
19 }
20 }
1 /**
2 * 注意:
3 * 1.泛型隻能使用引用類型
4 * 2.不同泛型類型的對象不能互相指派
5 */
6 public class TestGeneric {
7 public static void main(String[] args) {
8 //使用泛型類建立對象
9 MyGeneric<String> stringMyGeneric = new MyGeneric<>();
10 stringMyGeneric.t = "葫蘆娃";
11 stringMyGeneric.show("火娃");
12
13 MyGeneric<Integer> integerMyGeneric = new MyGeneric<>();
14 integerMyGeneric.t=20;
15 integerMyGeneric.show(30);
16 Integer integer = integerMyGeneric.getT();
17 System.out.println(integer);
18 }
19 }
泛型接口
1 /**
2 * 泛型接口
3 * 文法:接口名<T>
4 * 注意:不能建立泛型靜态常量
5 */
6 public interface MyInterface<T> {
7 //建立常量
8 String nameString="金剛大芭比";
9
10 //接口方法
11 T server(T t);
12 }
1 /**
2 * 實作接口時确定泛型類
3 */
4 public class MyInterfaceImpl implements MyInterface<String> {
5
6 @Override
7 public String server(String s) {
8 System.out.println(nameString);
9 System.out.println(s);
10 return s;
11 }
12 }
1 //測試
2 public class Application {
3 public static void main(String[] args) {
4 MyInterfaceImpl myInterface = new MyInterfaceImpl();
5 myInterface.server("xxx");
6 }
7 }
1 /**
2 * 實作接口時不确定泛型類
3 */
4 public class MyInterfaceImpl2<T> implements MyInterface<T>{
5 @Override
6 public T server(T t) {
7 System.out.println(nameString);
8 System.out.println(t);
9 return t;
10 }
11 }
1 //測試
2 public class Application {
3 public static void main(String[] args) {
4 MyInterfaceImpl2<Integer> integerMyInterfaceImpl2 = new MyInterfaceImpl2<>();
5 integerMyInterfaceImpl2.server(20);
6 }
7 }
泛型方法
1 /**
2 * 泛型方法
3 * 文法:<T> 傳回類型
4 */
5 public class MyGenericMethod {
6 public <T> void show(T t){
7 System.out.println("泛型方法"+t);
8 }
9 }
1 //測試
2 public class Application {
3 public static void main(String[] args) {
4 MyGenericMethod myGenericMethod = new MyGenericMethod();
5 myGenericMethod.show("金剛");
6 myGenericMethod.show(18);
7 }
8 }
泛型集合
- 概念:參數化類型、類型安全的集合,強制集合元素的類型必須一緻。
- 特點:
- 編譯時即可檢查,而非運作時抛出異常。
- 通路時,不必類型轉換(拆箱)。
- 不同泛型指尖引用不能互相指派,泛型不存在多态。
之前我們在建立LinkedList類型對象的時候并沒有使用泛型,但是進到它的源碼中會發現:
1 public class LinkedList<E>
2 extends AbstractSequentialList<E>
3 implements List<E>, Deque<E>, Cloneable, java.io.Serializable
4 {//略
它是一個泛型類,而我之前使用的時候并沒有傳遞,說明java文法是允許的,這個時候傳遞的類型是Object類,雖然它是所有類的父類,可以存儲任意的類型,但是在周遊、擷取元素時需要原來的類型就要進行強制轉換。這個時候就會出現一些問題,假如往連結清單裡存儲了許多不同類型的資料,在強轉的時候就要判斷每一個原來的類型,這樣就很容易出現錯誤。
Set集合概述
Set子接口
- 特點:無序、無下标、元素不可重複。
- 方法:全部繼承自Collection中的方法。
1 /**
2 * 測試Set接口的使用
3 * 特點:1.無序,沒有下标;2.重複
4 * 1.添加資料
5 * 2.删除資料
6 * 3.周遊【重點】
7 * 4.判斷
8 */
9 public class Demo01 {
10 public static void main(String[] args) {
11 Set<String> set = new HashSet<>();
12 //1.添加資料
13 set.add("火娃");
14 set.add("金娃");
15 set.add("木娃");
16 set.add("水娃");
17 //set.add("水娃");無法添加元素相同資料
18 System.out.println("元素個數為:"+set.size());
19 System.out.println(set.toString());
20
21 //2.删除資料
22 set.remove("水娃");
23 System.out.println("删除後:"+set.size());
24 System.out.println(set.toString());
25
26 //3.周遊
27 //3.1 使用增強for循環
28 for (String s:set) {
29 System.out.println(s);
30 }
31 //3.2 使用疊代器
32 Iterator<String> iterator = set.iterator();
33 while (iterator.hasNext()){
34 System.out.println(iterator.next());
35 }
36
37 //4. 判斷
38 System.out.println(set.isEmpty());//false
39 System.out.println(set.contains("火娃"));//true
40 }
41 }
Set實作類
HashSet【重點】
- 基于HashCode計算元素存放位置。
- 當存入元素的哈希碼相同時,會調用equals進行确認,如結果為true,則拒絕後者存入。
1 /**
2 * 人類
3 */
4 public class Person {
5 private String name;
6 private int age;
7
8 public Person(String name, int age) {
9 this.name = name;
10 this.age = age;
11 }
12
13 public Person() {
14 }
15
16 public String getName() {
17 return name;
18 }
19
20 public void setName(String name) {
21 this.name = name;
22 }
23
24 public int getAge() {
25 return age;
26 }
27
28 public void setAge(int age) {
29 this.age = age;
30 }
31
32 @Override
33 public String toString() {
34 return "Person{" +
35 "name='" + name + '\'' +
36 ", age=" + age +
37 '}';
38 }
39 }
1 /**
2 * HashSet集合的使用
3 * 存儲結構:哈希表(數組+連結清單+紅黑樹)
4 * 1.添加元素
5 * 2.删除元素
6 * 3.周遊
7 * 4.判斷
8 */
9 public class Demo02 {
10 public static void main(String[] args) {
11 HashSet<Person> hashSet=new HashSet<>();
12 Person p1=new Person("tang",21);
13 Person p2=new Person("he", 22);
14 Person p3=new Person("yu", 21);
15 //1.添加元素
16 hashSet.add(p1);
17 hashSet.add(p2);
18 hashSet.add(p3);
19 //重複,添加失敗
20 hashSet.add(p3);
21 //直接new一個相同屬性的對象,依然會被添加,不難了解。
22 //假如相同屬性便認為是同一個對象,怎麼修改?
23 hashSet.add(new Person("yu", 21));
24 System.out.println(hashSet.toString());
25 //2.删除元素
26 hashSet.remove(p2);
27 //3.周遊
28 //3.1 增強for
29 for (Person person : hashSet) {
30 System.out.println(person);
31 }
32 //3.2 疊代器
33 Iterator<Person> iterator=hashSet.iterator();
34 while (iterator.hasNext()) {
35 System.out.println(iterator.next());
36 }
37 //4.判斷
38 System.out.println(hashSet.isEmpty());
39 //直接new一個相同屬性的對象結果輸出是false,不難了解。
40 //注:假如相同屬性便認為是同一個對象,該怎麼做?
41 System.out.println(hashSet.contains(new Person("tang", 21)));
42 }
43 }
注:hashSet存儲過程:
- 根據hashCode計算儲存的位置,如果位置為空,則直接儲存,否則執行第二步。
- 執行equals方法,如果方法傳回true,則認為是重複,拒絕存儲,否則形成連結清單。
存儲過程實際上就是重複依據,要實作“注”裡的問題,可以重寫hashCode和equals代碼:
1 @Override
2 public int hashCode() {
3 final int prime = 31;
4 int result = 1;
5 result = prime * result + age;
6 result = prime * result + ((name == null) ? 0 : name.hashCode());
7 return result;
8 }
9 @Override
10 public boolean equals(Object obj) {
11 if (this == obj)
12 return true;
13 if (obj == null)
14 return false;
15 if (getClass() != obj.getClass())
16 return false;
17 Person other = (Person) obj;
18 if (age != other.age)
19 return false;
20 if (name == null) {
21 if (other.name != null)
22 return false;
23 } else if (!name.equals(other.name))
24 return false;
25 return true;
26 }
hashCode方法裡為什麼要使用31這個數字大概有兩個原因:
- 31是一個質數,這樣的數字在計算時可以盡量減少散列沖突。
- 可以提高執行效率,因為31*i=(i<<5)-i,31乘以一個數可以轉換成移位操作,這樣能快一點;但是也有網上一些人對這兩點提出質疑。
TreeSet
- 基于排序順序實作不重複。
- 實作了SortedSet接口,對集合元素自動排序。
- 元素對象的類型必須實作Comparable接口,指定排序規則。
- 通過CompareTo方法确定是否為重複元素。
1 /**
2 * 使用TreeSet儲存資料
3 * 存儲結構:紅黑樹
4 * 要求:元素類必須實作Comparable接口,compareTo方法傳回0,認為是重複元素
5 */
6 public class Demo01 {
7 public static void main(String[] args) {
8
9 TreeSet<Person> treeSet = new TreeSet<>();
10
11 Person p1 = new Person("it",12);
12 Person p2 = new Person("he",12);
13 Person p3 = new Person("she",12);
14
15 //1.添加元素
16 treeSet.add(p1);
17 treeSet.add(p2);
18 treeSet.add(p3);
19 treeSet.add(p3);//相同無法添加
20 //注:直接添加會報類型錯誤,需要實作Comparable接口
21 System.out.println("元素個數為:"+treeSet.size());
22 System.out.println(treeSet.toString());
23
24 //2.删除元素
25 treeSet.remove(p3);
26 treeSet.remove(new Person("she",12));
27 System.out.println(treeSet.toString());
28
29 //3.周遊
30 //3.1 增強for循環
31 for (Person person:treeSet) {
32 System.out.println(person);
33 }
34 //3.2 疊代器
35 Iterator<Person> iterator = treeSet.iterator();
36 while (iterator.hasNext()){
37 System.out.println(iterator.next());
38 }
39
40 //4.判斷
41 System.out.println(treeSet.contains(new Person("it",12)));
42 }
43 }
運作報錯,因為treeset是紅黑樹,目前代碼沒有定義比較的屬性,需要重寫Comparable方法
先檢視Comparable接口的源碼,發現隻有一個compareTo抽象方法,在Person類中實作它:
1 public class Person implements Comparable<Person> {
2 @Override
3 public int compareTo(Person o) {
4 int n1 = this.getName().compareTo(o.getName());//名字相同,傳回0,不同傳回其他數字
5 int n2 = this.getAge()-o.getAge();//比較年齡
6 return n1==0?n2:n1;//名字相同,傳回n2,名字不同,傳回n1
7 }
8 }
再次運作TreeSet的Demo01,運作成功
除了實作Comparable接口裡的比較方法,還有另外一種方法,TreeSet也提供了一個帶比較器Comparator的構造方法,使用匿名内部類來實作它:
1 /**
2 * TreeSet的使用
3 * Comparator:實作定制比較(比較器)
4 */
5 public class Demo02 {
6 public static void main(String[] args) {
7 TreeSet<Person> person = new TreeSet<Person>(new Comparator<Person>() {
8 @Override
9 public int compare(Person o1, Person o2) {
10 // 先按年齡比較
11 // 再按姓名比較
12 int n1=o1.getAge()-o2.getAge();
13 int n2=o1.getName().compareTo(o2.getName());
14 return n1==0?n2:n1;
15 }
16 });
17 Person p1 = new Person("it",12);
18 Person p2 = new Person("he",12);
19 Person p3 = new Person("she",12);
20
21 //1.添加元素
22 person.add(p1);
23 person.add(p2);
24 person.add(p3);
25 //注:直接添加會報類型錯誤,需要實作Comparable接口
26 System.out.println("元素個數為:"+person.size());
27 System.out.println(person.toString());
28 }
29 }
接下來我們來做一個小案例:
1 /**
2 * 要求:使用TreeSet集合實作字元串按照長度進行排序
3 * helloworld tangrui hechengyang wangzixu yuguoming
4 * Comparator接口實作定制比較
5 */
6 public class Demo03 {
7 public static void main(String[] args) {
8 TreeSet<String> s = new TreeSet<>(new Comparator<String>() {
9 @Override
10 //1.先比較長度
11 //2.在比較字元串
12 public int compare(String o1, String o2) {
13 int n1 = o1.length()-o2.length();
14 int n2 = o1.compareTo(o2);
15 return n1==0?n2:n1;
16 }
17 });
18 s.add("hello world");
19 s.add("hello Java");
20 s.add("hello Python");
21 System.out.println(s.toString());
22 }
23 }
Map體系集合
- Map接口的特點:
- 用于存儲任意鍵值對(Key-Value)。
- 鍵:無序、無下标、不允許重複(唯一)。
- 值:無序、無下标、允許重複。
Map集合概述
- 特點:存儲一對資料(Key-Value),無序、無下标,鍵不可重複。
-
-
//将對象存入到集合中,關聯鍵值。key重複則覆寫原值。V put(K key,V value)
-
-
//根據鍵擷取相應的值。Object get(Object key)
-
//傳回所有的keySet<K>
-
//傳回包含所有值的Collection集合。Collection<V> values()
-
//鍵值比對的set集合Set<Map.Entry<K,V>>
-
1 /**
2 * Map接口的使用
3 * 特點:1.存儲鍵值對 2.鍵不能重複,值可以重複 3.無序
4 */
5 public class Demo01 {
6 public static void main(String[] args) {
7 //建立Map集合
8 HashMap<String, String> map = new HashMap<>();
9
10 //1.添加元素
11 map.put("cn","中國");
12 map.put("uk","英國");
13 map.put("usa","美國");
14 map.put("cn","Chinse");//相同key添加,會替換之前的value值
15 System.out.println("元素個數為:"+map.size());
16 System.out.println(map.toString());
17
18 //2.删除
19 map.remove("usa");
20 System.out.println("删除後元素個數為:"+map.size());
21 System.out.println(map.toString());
22
23 //3.周遊
24 //3.1 使用keyset(),先擷取key,再使用get(key)方法擷取value值
25 Set<String> keySet = map.keySet();
26 for (String key:keySet) {
27 System.out.println(key+"-----"+map.get(key));
28 }
29 //簡寫
30 for (String s:map.keySet()) {
31 System.out.println(s+"-----"+map.get(s));
32 }
33 //3.2 使用entrySet()方法;效率更高,把key和value都拿出來了,不需要為了value再去多做一遍查詢key的操作
34 Set<Map.Entry<String, String>> entries = map.entrySet();
35 for (Map.Entry<String,String> entry:entries) {
36 System.out.println(entry.getKey()+"------"+entry.getValue());
37 }
38 //簡寫
39 for (Map.Entry<String,String> entry:map.entrySet()) {
40 System.out.println(entry.getKey()+"------"+entry.getValue());
41 }
42
43
44 }
45 }
keySet周遊和entrySet的差別
Map集合的實作類
HashMap【重點】
- JDK1.2版本,線程不安全,運作效率快;允許用null作為key或是value。
1 /**
2 * 學生類
3 */
4 public class Student {
5 private String name;
6 private int age;
7
8 public String getName() {
9 return name;
10 }
11
12 public void setName(String name) {
13 this.name = name;
14 }
15
16 public int getAge() {
17 return age;
18 }
19
20 public void setAge(int age) {
21 this.age = age;
22 }
23
24 @Override
25 public String toString() {
26 return "Student{" +
27 "name='" + name + '\'' +
28 ", age=" + age +
29 '}';
30 }
31
32 public Student(String name, int age) {
33 this.name = name;
34 this.age = age;
35 }
36 }
1 /**
2 * HashMap的使用
3 * 存儲結構:哈希表(數組+連結清單+紅黑樹)
4 */
5 public class Demo01 {
6 public static void main(String[] args) {
7 HashMap<Student, String> hashMap = new HashMap<>();
8 Student p1 = new Student("趙一",11);
9 Student p2 = new Student("王二",11);
10 Student p3 = new Student("張三",11);
11 Student p4 = new Student("李四",11);
12 //1.添加元素
13 hashMap.put(p1,"北京");
14 hashMap.put(p2,"上海");
15 hashMap.put(p3,"廣州");
16 hashMap.put(p4,"曹縣");
17 hashMap.put(p4,"曹縣(山東)");//不能添加重複的key,但是會将value更新
18
19 //👇,上面已經有一個李四的key了,通過這個還可以繼續添加,那能不能讓系統根據key的資料判重,而不是根據記憶體位址?
20 hashMap.put(new Student("李四",11),"南京");
21 System.out.println("元素個數為:"+hashMap.size());
22 System.out.println(hashMap.toString());
23
24 //2.删除元素
25 hashMap.remove(p2);
26 System.out.println(hashMap.toString());
27
28 //3.周遊
29 //3.1 使用keySet周遊
30 for (Student s:hashMap.keySet()) {
31 System.out.println(s+"------"+hashMap.get(s));
32 }
33 //3.2 使用entrySet周遊
34 for (Map.Entry<Student,String> entry:hashMap.entrySet()) {
35 System.out.println(entry.getKey()+"------"+entry.getValue());
36 }
37
38 //4.判斷
39 System.out.println(hashMap.containsKey(p1));
40 System.out.println(hashMap.containsKey(new Student("李四",11)));
41 System.out.println(hashMap.containsValue("曹縣(山東)"));
42 }
43 }
- 注:和之前說過的HashSet類似,重複依據是hashCode和equals方法,重寫即可:
1 @Override
2 public int hashCode() {
3 final int prime = 31;
4 int result = 1;
5 result = prime * result + id;
6 result = prime * result + ((name == null) ? 0 : name.hashCode());
7 return result;
8 }
9 @Override
10 public boolean equals(Object obj) {
11 if (this == obj)
12 return true;
13 if (obj == null)
14 return false;
15 if (getClass() != obj.getClass())
16 return false;
17 Student other = (Student) obj;
18 if (id != other.id)
19 return false;
20 if (name == null) {
21 if (other.name != null)
22 return false;
23 } else if (!name.equals(other.name))
24 return false;
25 return true;
26 }
HashMap源碼分析
- 預設初始化容量:
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16
- 數組最大容量:
static final int MAXIMUM_CAPACITY = 1 << 30;
- 數組最大容量:
- 預設加載因子:
static final float DEFAULT_LOAD_FACTOR = 0.75f;
- 連結清單調整為紅黑樹的連結清單長度門檻值(JDK1.8):
static final int TREEIFY_THRESHOLD = 8;
- 紅黑樹調整為連結清單的連結清單長度門檻值(JDK1.8):
static final int UNTREEIFY_THRESHOLD = 6;
- 連結清單調整為紅黑樹的數組最小門檻值(JDK1.8):
static final int MIN_TREEIFY_CAPACITY = 64;
- HashMap存儲的數組:
transient Node<K,V>[] table;
- HashMap存儲的元素個數:
transient int size;
- 預設加載因子是什麼?
- 就是判斷數組是否擴容的一個因子。假如數組容量為100,如果HashMap的存儲元素個數超過了100*0.75=75,那麼就會進行擴容。
- 連結清單調整為紅黑樹的連結清單長度門檻值是什麼?
- 假設在數組中下标為3的位置已經存儲了資料,當新增資料時通過哈希碼得到的存儲位置又是3,那麼就會在該位置形成一個連結清單,當連結清單過長時就會轉換成紅黑樹以提高執行效率,這個門檻值就是連結清單轉換成紅黑樹的最短連結清單長度;
- 紅黑樹調整為連結清單的連結清單長度門檻值是什麼?
- 當紅黑樹的元素個數小于該門檻值時就會轉換成連結清單。
- 連結清單調整為紅黑樹的數組最小門檻值是什麼?
- 并不是隻要連結清單長度大于8就可以轉換成紅黑樹,在前者條件成立的情況下,數組的容量必須大于等于64才會進行轉換。
HashMap的數組table存儲的就是一個個的Node<K,V>類型,很清晰地看到有一對鍵值,還有一個指向next的指針(以下隻截取了部分源碼):
1 static class Node<K,V> implements Map.Entry<K,V> {
2 final K key;
3 V value;
4 Node<K,V> next;
5 }
之前的代碼中在new對象時調用的是HashMap的無參構造方法,進入到該構造方法的源碼檢視一下:
1 public HashMap() {
2 this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
3 }
發現沒什麼内容,隻是指派了一個預設加載因子;而在上文我們觀察到源碼中table和size都沒有賦予初始值,說明剛建立的HashMap對象沒有配置設定容量,并不擁有預設的16個空間大小,這樣做的目的是為了節約空間,此時table為null,size為0。
當我們往對象裡添加元素時調用put方法:
1 public V put(K key, V value) {
2 return putVal(hash(key), key, value, false, true);
3 }
put方法把key和value傳給了putVal,同時還傳入了一個hash(Key)所傳回的值,這是一個産生哈希值的方法,再進入到putVal方法(部分源碼):
1 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
2 boolean evict) {
3 Node<K,V>[] tab; Node<K,V> p; int n, i;
4 if ((tab = table) == null || (n = tab.length) == 0)
5 n = (tab = resize()).length;
6 if ((p = tab[i = (n - 1) & hash]) == null)
7 tab[i] = newNode(hash, key, value, null);
8 else{
9 //略
10 }
11 }
這裡面建立了一個tab數組和一個Node變量p,第一個if實際是判斷table是否為空,而我們現在隻關注剛建立HashMap對象時的狀态,此時tab和table都為空,滿足條件,執行内部代碼,這條代碼其實就是把resize()所傳回的結果賦給tab,n就是tab的長度,resize顧名思義就是重新調整大小。檢視resize()源碼(部分):
1 final Node<K,V>[] resize() {
2 Node<K,V>[] oldTab = table;
3 int oldCap = (oldTab == null) ? 0 : oldTab.length;
4 int oldThr = threshold;
5 if (oldCap > 0);
6 else if (oldThr > 0);
7 else { // zero initial threshold signifies using defaults
8 newCap = DEFAULT_INITIAL_CAPACITY;
9 newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
10 }
11 @SuppressWarnings({"rawtypes","unchecked"})
12 Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
13 table = newTab;
14 return newTab;
15 }
該方法首先把table及其長度指派給oldTab和oldCap;threshold是門檻值的意思,此時為0,是以前兩個if先不管,最後else裡newCap的值為預設初始化容量16;往下建立了一個newCap大小的數組并将其賦給了table,剛建立的HashMap對象就在這裡獲得了初始容量。然後我們再回到putVal方法,第二個if就是根據哈希碼得到的tab中的一個位置是否為空,為空便直接添加元素,此時數組中無元素是以直接添加。至此HashMap對象就完成了第一個元素的添加。當添加的元素超過16*0.75=12時,就會進行擴容:
1 final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict){
2 if (++size > threshold)
3 resize();
4 }
擴容的代碼如下(部分):
1 final Node<K,V>[] resize() {
2 int oldCap = (oldTab == null) ? 0 : oldTab.length;
3 int newCap;
4 if (oldCap > 0) {
5 if (oldCap >= MAXIMUM_CAPACITY) {//略}
6 else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
7 oldCap >= DEFAULT_INITIAL_CAPACITY)
8 }
9 }
核心部分是else if裡的移位操作,也就是說每次擴容都是原來大小的兩倍。
- *注**:額外說明的一點是在JDK1.8以前連結清單是頭插入,JDK1.8以後連結清單是尾插入。
HashSet源碼分析
了解完HashMap之後,再回過頭來看之前的HashSet源碼,為什麼放在後面寫你們看一下源碼就知道了(部分):
1 public class HashSet<E>
2 extends AbstractSet<E>
3 implements Set<E>, Cloneable, java.io.Serializable
4 {
5 private transient HashMap<E,Object> map;
6 private static final Object PRESENT = new Object();
7 public HashSet() {
8 map = new HashMap<>();
9 }
10 }
可以看見HashSet的存儲結構就是HashMap,那它的存儲方式是怎樣的呢?可以看一下add方法:
1 public boolean add(E e) {
2 return map.put(e, PRESENT)==null;
3 }
很明了地發現它的add方法調用的就是map的put方法,把元素作為map的key傳進去的。。
Hashtable
- JDK1.0版本,線程安全,運作效率慢;不允許null作為key或是value。
-
初始容量11,加載因子0.75。
這個集合在開發過程中已經不用了,稍微了解即可。
Properties
- Hashtable的子類,要求key和value都是String。通常用于配置檔案的讀取。
它繼承了Hashtable的方法,與流關系密切,此處不詳解。
TreeMap
- 實作了SortedMap接口(是Map的子接口),可以對key自動排序。
1 /**
2 * TreeMap的使用
3 * 存儲結構:紅黑樹
4 */
5 public class Demo3 {
6 public static void main(String[] args) {
7 TreeMap<Student, Integer> treeMap=new TreeMap<Student, Integer>();
8 Student s1=new Student("tang", 36);
9 Student s2=new Student("yu", 101);
10 Student s3=new Student("he", 10);
11 //1.添加元素
12 treeMap.put(s1, 21);
13 treeMap.put(s2, 22);
14 treeMap.put(s3, 21);
15 //不能直接列印,需要實作Comparable接口,因為紅黑樹需要比較大小
16 System.out.println(treeMap.toString());
17 //2.删除元素
18 treeMap.remove(new Student("he", 10));
19 System.out.println(treeMap.toString());
20 //3.周遊
21 //3.1 使用keySet()
22 for (Student key : treeMap.keySet()) {
23 System.out.println(key+" "+treeMap.get(key));
24 }
25 //3.2 使用entrySet()
26 for (Entry<Student, Integer> entry : treeMap.entrySet()) {
27 System.out.println(entry.getKey()+" "+entry.getValue());
28 }
29 //4.判斷
30 System.out.println(treeMap.containsKey(s1));
31 System.out.println(treeMap.isEmpty());
32 }
33 }
在學生類中實作Comparable接口:
1 public class Student implements Comparable<Student>{
2 @Override
3 public int compareTo(Student o) {
4 int n1=this.id-o.id;
5 return n1;
6 }
除此之外還可以使用比較器來定制比較:
1 TreeMap<Student, Integer> treeMap2=new TreeMap<Student, Integer>(new Comparator<Student>() {
2 @Override
3 public int compare(Student o1, Student o2) {
4 // 略
5 return 0;
6 }
7 });
TreeSet源碼
和HashSet類似,放在TreeMap之後講便一目了然(部分):
1 public class TreeSet<E> extends AbstractSet<E>
2 implements NavigableSet<E>, Cloneable, java.io.Serializable
3 {
4 private transient NavigableMap<E,Object> m;
5 private static final Object PRESENT = new Object();
6 TreeSet(NavigableMap<E,Object> m) {
7 this.m = m;
8 }
9 public TreeSet() {
10 this(new TreeMap<E,Object>());
11 }
12 }
TreeSet的存儲結構實際上就是TreeMap,再來看其存儲方式:
1 public boolean add(E e) {
2 return m.put(e, PRESENT)==null;
3 }
它的add方法調用的就是TreeMap的put方法,将元素作為key傳入到存儲結構中。
Collections工具類
- 概念:集合工具類,定義了除了存取以外的集合常用方法。
-
-
//反轉集合中元素的順序public static void reverse(List<?> list)
-
//随機重置集合元素的順序public static void shuffle(List<?> list)
-
//升序排序(元素類型必須實作Comparable接口)public static void sort(List<T> list)
-
1 /**
2 * 示範Collections工具類的使用
3 *
4 */
5 public class Demo4 {
6 public static void main(String[] args) {
7 List<Integer> list=new ArrayList<Integer>();
8 list.add(20);
9 list.add(10);
10 list.add(30);
11 list.add(90);
12 list.add(70);
13
14 //sort排序
15 System.out.println(list.toString());
16 Collections.sort(list);
17 System.out.println(list.toString());
18 System.out.println("---------");
19
20 //binarySearch二分查找
21 int i=Collections.binarySearch(list, 10);
22 System.out.println(i);
23
24 //copy複制
25 List<Integer> list2=new ArrayList<Integer>();
26 for(int i1=0;i1<5;++i1) {
27 list2.add(0);
28 }
29 //該方法要求目标元素容量大于等于源目标
30 Collections.copy(list2, list);
31 System.out.println(list2.toString());
32
33 //reserve反轉
34 Collections.reverse(list2);
35 System.out.println(list2.toString());
36
37 //shuffle 打亂
38 Collections.shuffle(list2);
39 System.out.println(list2.toString());
40
41 //補充:list轉成數組
42 Integer[] arr=list.toArray(new Integer[0]);
43 System.out.println(arr.length);
44 //補充:數組轉成集合
45 String[] nameStrings= {"tang","he","yu"};
46 //受限集合,不能添加和删除
47 List<String> list3=Arrays.asList(nameStrings);
48 System.out.println(list3);
49
50 //注:基本類型轉成集合時需要修改為包裝類
51 }
52 }