日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

java 集合 接口_Java集合之Collection接口

發(fā)布時(shí)間:2023/11/27 生活经验 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 集合 接口_Java集合之Collection接口 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1 - Java集合介紹

/*

1. 一方面, 面向?qū)ο笳Z言對事物的體現(xiàn)都是以對象的形式,為了方便對多個(gè)對象 的操作,就要對對象進(jìn)行存儲。

2. 另一方面,使用Array存儲對象方面具有一些弊 端,而Java 集合就像一種容器,可以動(dòng)態(tài)地把多個(gè)對象的引用放入容器中。

①數(shù)組在內(nèi)存存儲方面的特點(diǎn):

數(shù)組初始化以后,長度就確定了。

數(shù)組聲明的類型,就決定了進(jìn)行元素初始化時(shí)的類型

②數(shù)組在存儲數(shù)據(jù)方面的弊端:

數(shù)組初始化以后,長度就不可變了,不便于擴(kuò)展

數(shù)組中提供的屬性和方法少,不便于進(jìn)行添加、刪除、插入等操作,且效率不高。 同時(shí)無法直接獲取存儲元素的個(gè)數(shù)

數(shù)組存儲的數(shù)據(jù)是有序的、可以重復(fù)的。---->存儲數(shù)據(jù)的特點(diǎn)單一

3. Java 集合類可以用于存儲數(shù)量不等的多個(gè)對象,還可用于保存具有映射關(guān)系的關(guān)聯(lián)數(shù)組

*/

packagecom.lzh.java1;/*集合框架概述:

1. 集合、數(shù)組都是對多個(gè)數(shù)據(jù)進(jìn)行存儲操作的結(jié)構(gòu),簡稱Java容器。說明:此時(shí)的存儲,主要指的是內(nèi)存層面的存儲,不涉及到硬盤層面的存儲。

2. 數(shù)組在存儲多個(gè)數(shù)據(jù)方面的特點(diǎn):

> 一旦初始化以后,其長度就確定了

> 數(shù)組一旦定義好,其元素的類型也確定了,也就只能操作指定類型的數(shù)據(jù)了,比如:String[] array;int[] arr

3. 數(shù)組在存儲多個(gè)數(shù)據(jù)方面的缺點(diǎn):

> 一旦初始化以后,其長度就不可修改

> 數(shù)組中提供的方法非常有限,對于添加、刪除、插入數(shù)據(jù)等操作,非常不便

> 獲取數(shù)組中實(shí)際元素的個(gè)數(shù)的需求,數(shù)組沒有現(xiàn)成的屬性或方法可用

> 數(shù)組存儲數(shù)據(jù)的特點(diǎn):有序、可重復(fù)。對于無序、不可重復(fù)的需求,不能滿足*/

public classCollectionTest {

}

集合框架概述

2 - Java集合的使用場景

3 - Java集合Collection 和 Map 兩種體系

/*

Java 集合可分為 Collection 和 Map 兩種體系:

1 Collection接口:單列數(shù)據(jù),定義了存取一組對象的方法的集合

①List:元素有序、可重復(fù)的集合 --> "動(dòng)態(tài)"數(shù)組

②Set:元素?zé)o序、不可重復(fù)的集合 --> 數(shù)學(xué)層面的集合(無序,確定,互異)

2 Map接口:雙列數(shù)據(jù),保存具有映射關(guān)系“key-value對”的集合 --> 數(shù)學(xué)函數(shù) y = f(x)

*/

Collection接口:單列集合,用來存儲一個(gè)一個(gè)的對象。其中List接口:用來存儲,有序可重復(fù)的數(shù)據(jù),Set接口:用來存儲,無序,不可重復(fù)的數(shù)據(jù)

Map接口:雙列集合,用來存儲一對(key - value)的一對數(shù)據(jù)

4 - Collection接口方法

/*

Collection接口

1 Collection 接口是 List、Set 和 Queue 接口的父接口,該接口里定義的方法 既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。

2JDK不提供此接口的任何直接實(shí)現(xiàn),而是提供更具體的子接口(如:Set和List)實(shí)現(xiàn)。

3 在Java5 之前,Java 集合會(huì)丟失容器中所有對象的數(shù)據(jù)類型,把所有對象都 當(dāng)成 Object 類型處理;從 JDK 5.0 增加了泛型以后,Java 集合可以記住容器中對象的數(shù)據(jù)類型

4結(jié)論:向Collection接口的實(shí)現(xiàn)類的對象中添加數(shù)據(jù)obj時(shí),要求obj所在類要重寫equals()

*/

/*1、添加

① add(Object obj)

② addAll(Collection coll)

2、獲取有效元素的個(gè)數(shù)

① int size()

3、清空集合

① void clear()

4、是否是空集合

① boolean isEmpty()

5、是否包含某個(gè)元素

① boolean contains(Object obj):是通過元素的equals方法來判斷是否 是同一個(gè)對象

② boolean containsAll(Collection c):也是調(diào)用元素的equals方法來比 較的。拿兩個(gè)集合的元素挨個(gè)比較。

6、刪除

① boolean remove(Object obj) :通過元素的equals方法判斷是否是 要?jiǎng)h除的那個(gè)元素。只會(huì)刪除找到的第一個(gè)元素

② boolean removeAll(Collection coll):取當(dāng)前集合的差集

7、取兩個(gè)集合的交集

① boolean retainAll(Collection c):把交集的結(jié)果存在當(dāng)前集合中,不 影響c

8、集合是否相等

① boolean equals(Object obj)

9、轉(zhuǎn)成對象數(shù)組

① Object[] toArray()

10、獲取集合對象的哈希值

① hashCode()

11、遍歷

① iterator():返回迭代器對象,用于集合遍歷*/

Collection接口中的方法

packagecom.lzh.java1;importorg.junit.Test;import java.util.*;/*Collection接口中聲明的方法測試

結(jié)論:

向Collection接口的實(shí)現(xiàn)類的對象中添加數(shù)據(jù)obj時(shí),要求obj所在類要重寫equals()*/

public classCollectionTest {//Collection接口中方法的使用

@Testpublic voidtest1(){

Collection coll= newArrayList();//add(Object e) 將元素e添加到集合中

coll.add(123); //自動(dòng)裝箱

coll.add("a");

coll.add("b");

coll.add(newDate());//size() 獲取集合中元素的個(gè)數(shù)

System.out.println(coll.size());//addAll(Collection coll1) 將集合coll1中的所有元素添加到當(dāng)前的集合中

Collection coll1 = newArrayList();

coll1.add(222);

coll1.addAll(coll);

System.out.println(coll1.size());//5

System.out.println(coll1);//isEmpty() 判斷當(dāng)前集合是否為空

System.out.println(coll.isEmpty()); //false//clear() 清空集合元素

coll.clear();

System.out.println(coll.isEmpty());//true

}

@Testpublic voidtest2(){

Collection collection1= newArrayList();

collection1.add(13);

collection1.add(22);

collection1.add(new String("alex"));

collection1.add(false);

collection1.add(new Person("alex",22));//System.out.println(collection1);//contains(Object obj):是通過元素的equals方法來判斷是否 是同一個(gè)對象

boolean isContains = collection1.contains(13);

System.out.println(isContains);

System.out.println(collection1.size());

System.out.println(collection1.contains(new Person("alex",22))); //true//containsAll(Collection coll1) 判斷形參coll1中的所有元素是否都存在于當(dāng)前集合中。

Collection collection2 = Arrays.asList(13,false);

System.out.println(collection1.containsAll(collection2));//true

}

@Testpublic voidtest3(){//集合 --> 數(shù)組 toArray() 返回值為 Object[]

Collection collection = newArrayList();for(int i = 0;i < 5;i++){

collection.add(i);

}

Object[] arrays=collection.toArray();

System.out.println(arrays.getClass());//class [Ljava.lang.Object;//遍歷數(shù)組

for(int i = 0;i < arrays.length;i++){

System.out.println(arrays[i]);

}//數(shù)組 --> 集合 調(diào)用Arrays類的靜態(tài)方法asList()

Collection collection1 = Arrays.asList(11,"adf",22);

System.out.println(collection1.getClass());//class java.util.Arrays$ArrayList

}

@Testpublic voidtest4(){//iterator() 返回Iterator接口的實(shí)例,用于遍歷集合元素。

Collection collection = newArrayList();for(int i = 0;i < 5;i++){

collection.add("list"+1);

}

Iterator iterator=collection.iterator();//集合元素的遍歷操作,使用迭代器Iterator接口

}

}classPerson{privateString name;private intage;publicPerson(){}public Person(String name,intage){this.name =name;this.age =age;

}

@Overridepublic booleanequals(Object o) {

System.out.println("執(zhí)行 equals()...");if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;

Person person=(Person) o;return age == person.age &&Objects.equals(name, person.name);

}

@Overridepublic inthashCode() {returnObjects.hash(name, age);

}

}

Collection接口中聲明的方法測試

5 - Iterator迭代器接口

/*

Iterator迭代器介紹:

1 Iterator對象稱為迭代器(設(shè)計(jì)模式的一種),主要用于遍歷 Collection 集合中的元素。

2 GOF給迭代器模式的定義為:提供一種方法訪問一個(gè)容器(container)對象中各個(gè)元 素,而又不需暴露該對象的內(nèi)部細(xì)節(jié)。迭代器模式,就是為容器而生。類似于“公 交車上的售票員”、“火車上的乘務(wù)員”、“空姐”。

3 Collection接口繼承了java.lang.Iterable接口,該接口有一個(gè)iterator()方法,那么所 有實(shí)現(xiàn)了Collection接口的集合類都有一個(gè)iterator()方法,用以返回一個(gè)實(shí)現(xiàn)了 Iterator接口的對象。

4 Iterator 僅用于遍歷集合,Iterator 本身并不提供承裝對象的能力。如果需要?jiǎng)?chuàng)建 Iterator 對象,則必須有一個(gè)被迭代的集合。

5 集合對象每次調(diào)用iterator()方法都得到一個(gè)全新的迭代器對象,默認(rèn)游標(biāo)都在集合 的第一個(gè)元素之前

*/

Iterator接口的方法

packagecom.lzh.java1;importorg.junit.Test;importjava.util.ArrayList;importjava.util.Collection;importjava.util.Iterator;/*集合元素的遍歷操作,使用迭代器Iterator接口

1. 內(nèi)部的方法:hasNext() 和 next()

2. 集合對象每次調(diào)用iterator()方法都得到一個(gè)全新的迭代器對象,默認(rèn)游標(biāo)都在集合的第一個(gè)元素之前

3. 內(nèi)部定義了remove(),可以在遍歷的時(shí)候,刪除集合中的元素,此方法不同于集合直接調(diào)用remove()*/

public classIteratorTest {

@Testpublic voidtest1(){//iterator() 返回Iterator接口的實(shí)例,用于遍歷集合元素。

Collection collection = newArrayList();for(int i = 0;i < 5;i++){

collection.add("list"+i);

}

Iterator iterator=collection.iterator();//遍歷集合:方式1 不推薦使用

for(int i = 0;i < collection.size();i++){

System.out.println(iterator.next());//超過5次就報(bào)錯(cuò)(局限性)

}//遍歷集合:方式2 推薦使用//hasNext()與next()搭配使用

while(iterator.hasNext()){

System.out.println(iterator.next());

}

}

@Testpublic voidtest2(){//iterator中的remove()

Collection collection = newArrayList();for(int i = 0;i < 5;i++){

collection.add("list"+i);

}

Iterator iterator=collection.iterator();while(iterator.hasNext()){if("list2".equals(iterator.next())){

iterator.remove();

}

}

Iterator iterator1= collection.iterator(); //重新獲取迭代器

while(iterator1.hasNext()) {

System.out.println(iterator1.next());

}/*注意:

1 Iterator可以刪除集合的元素,但是是遍歷過程中通過迭代器對象的remove方 法,不是集合對象的remove方法。

2 如果還未調(diào)用next()或在上一次調(diào)用 next 方法之后已經(jīng)調(diào)用了 remove 方法, 再調(diào)用remove都會(huì)報(bào)IllegalStateException。*/}

}

迭代器Iterator接口的使用

迭代器的執(zhí)行原理

6 - 使用 foreach 循環(huán)遍歷集合元素

/*

foreach循環(huán):

1 Java 5.0 提供了 foreach 循環(huán)迭代訪問 Collection和數(shù)組。

2 遍歷操作不需獲取Collection或數(shù)組的長度,無需使用索引訪問元素。

3 遍歷集合的底層調(diào)用Iterator完成操作。

4 foreach還可以用來遍歷數(shù)組。

*/

packagecom.lzh.java1;importorg.junit.Test;importjava.util.ArrayList;importjava.util.Collection;importjava.util.Iterator;/*1 Java 5.0 提供了 foreach 循環(huán)迭代訪問 Collection和數(shù)組。

2 遍歷操作不需獲取Collection或數(shù)組的長度,無需使用索引訪問元素。

3 遍歷集合的底層調(diào)用Iterator完成操作。

4 foreach還可以用來遍歷數(shù)組。*/

public classforeachTest {

@Testpublic voidtest1(){

Collection collection= newArrayList();for(int i = 0;i < 5;i++){

collection.add("list"+i);

}//for(集合中元素的類型 局部變量 : 集合對象/數(shù)組){}//內(nèi)部任然調(diào)用迭代器

for(Object i:collection){

System.out.println(i);

}

}//遍歷數(shù)組

@Testpublic voidtest2(){int[] intArray = new int[]{1,2,3,4,5,6,7,8,9,10};for(inti:intArray){

System.out.println(i);

}

}//面試題:輸出結(jié)果?

@Testpublic voidtest3(){

String[] arr= new String[3];for(String i:arr){

i= "mm";

System.out.println(i);

}for(int i = 0;i < arr.length;i++){

System.out.println(arr[i]);//null

}

}

}

foreach循環(huán)的使用

7 - Collection子接口之一:List接口

/*

List接口:

1 鑒于Java中數(shù)組用來存儲數(shù)據(jù)的局限性,我們通常使用List替代數(shù)組

2 List集合類中元素有序、且可重復(fù),集合中的每個(gè)元素都有其對應(yīng)的順序索引。

3 List容器中的元素都對應(yīng)一個(gè)整數(shù)型的序號記載其在容器中的位置,可以根據(jù) 序號存取容器中的元素。

4 JDK API中List接口的實(shí)現(xiàn)類常用的有:ArrayList、LinkedList和Vector。

*/

/*List接口:"動(dòng)態(tài)"數(shù)組

List接口的3個(gè)實(shí)現(xiàn)類:ArrayList、LinkedList和Vector

面試題:ArrayList \ LinkedList \ Vector 3者之間的異同?

同:3個(gè)類都實(shí)現(xiàn)了List接口,存儲數(shù)據(jù)的特點(diǎn)相同(有序,可重復(fù))

異:

ArrayList(List接口主要實(shí)現(xiàn)類):線程不安全,執(zhí)行效率高。底層用Object[] elementData數(shù)組進(jìn)行存儲

LinkedList:對于頻繁的插入、刪除操作,使用此類效率比ArrayList高;底層使用雙向列表存儲

Vector(List接口古老實(shí)現(xiàn)類):線程安全,執(zhí)行效率偏低。底層用Object[] elementData數(shù)組進(jìn)行存儲

ArrayList源碼分析:

JDK7

ArrayList list = new ArrayList(); // 底層創(chuàng)建了長度為10的Object[] 數(shù)組elementData

list.add(123); // elementData[0] = new Integer(123);

...

list.add(11); // 如果此次的添加導(dǎo)致底層elementData數(shù)組容量不夠,則擴(kuò)容。默認(rèn)情況下,擴(kuò)容為原來的容量的1.5倍,同時(shí)需要將原有數(shù)組中的數(shù)據(jù)復(fù)制到新的數(shù)組中。

結(jié)論:建議開發(fā)中使用帶參的構(gòu)造器:ArrayList list = new ArrayList(int capacity);

JDK8 中ArrayList的變化

ArrayList list = new ArrayList(); // 底層Object[] elementData初始化為{},并沒有創(chuàng)建長度為10的數(shù)組

list.add(123); // 第一次調(diào)用add()時(shí),底層才創(chuàng)建了長度為10的數(shù)組,并將數(shù)據(jù)123添加到elementData[0]

...

后續(xù)的擴(kuò)容問題與JDK7一樣

結(jié)論:JDK7中的ArrayList的對象的創(chuàng)建類似于單例模式的餓漢式,而JDK8中ArrayList的對象的創(chuàng)建類似于單例模式的懶漢式,延遲了數(shù)組的創(chuàng)建,節(jié)省內(nèi)存。

LinkedList的源碼分析:

LinkedList list = new LinkedList(); // 內(nèi)部聲明了Node類型的first和last屬性,默認(rèn)值為null

list.add(123); // 將123封裝到Node中,創(chuàng)建Node對象

其中。Node定義為:體現(xiàn)了LinkedList的雙向鏈表的說法

private static class Node {

E item;

Node next;

Node prev;

Node(Node prev, E element, Node next) {

this.item = element;

this.next = next;

this.prev = prev;

}

}*/

面試題:ArrayList \ LinkedList \ Vector 3者之間的異同?

List實(shí)現(xiàn)類之一:ArrayList

1 ArrayList 是 List 接口的典型實(shí)現(xiàn)類、主要實(shí)現(xiàn)類

2 本質(zhì)上,ArrayList是對象引用的一個(gè)”變長”數(shù)組

3 ArrayList的JDK1.8之前與之后的實(shí)現(xiàn)區(qū)別?

① JDK1.7:ArrayList像餓漢式,直接創(chuàng)建一個(gè)初始容量為10的數(shù)組

② JDK1.8:ArrayList像懶漢式,一開始創(chuàng)建一個(gè)長度為0的數(shù)組,當(dāng)添加第一個(gè)元 素時(shí)再創(chuàng)建一個(gè)始容量為10的數(shù)組

4 Arrays.asList(…) 方法返回的 List 集合,既不是ArrayList 實(shí)例,也不是 Vector 實(shí)例。 Arrays.asList(…) 返回值是一個(gè)固定長度的 List 集合

List實(shí)現(xiàn)類之二:LinkedList

1 對于頻繁的插入或刪除元素的操作,建議使用LinkedList類,效率較高

2 新增方法:

1 void addFirst(Object obj)

2 void addLast(Object obj)

3 Object getFirst()

4 Object getLast()

5 Object removeFirst()

6 Object removeLast()

3 LinkedList:雙向鏈表,內(nèi)部沒有聲明數(shù)組,而是定義了Node類型的first和last, 用于記錄首末元素。同時(shí),定義內(nèi)部類Node,作為LinkedList中保存數(shù)據(jù)的基 本結(jié)構(gòu)。Node除了保存數(shù)據(jù),還定義了兩個(gè)變量:

1 prev變量記錄前一個(gè)元素的位置

1 next變量記錄下一個(gè)元素的位置

List 實(shí)現(xiàn)類之三:Vector

1 Vector 是一個(gè)古老的集合,JDK1.0就有了。大多數(shù)操作與ArrayList 相同,區(qū)別之處在于Vector是線程安全的。

2 在各種list中,最好把ArrayList作為缺省選擇。當(dāng)插入、刪除頻繁時(shí), 使用LinkedList;Vector總是比ArrayList慢,所以盡量避免使用。

3 新增方法:

1 void addElement(Object obj)

2 void insertElementAt(Object obj,int index)

3?void setElementAt(Object obj,int index)

4 void removeElement(Object obj)

5 void removeAllElements()

/*List除了從Collection集合繼承的方法外,List 集合里添加了一些根據(jù)索引來 操作集合元素的方法。

1 void add(int index, Object ele) 在index位置插入ele元素

2 boolean addAll(int index, Collection eles) 從index位置開始將eles中 的所有元素添加進(jìn)來

3 Object get(int index) 獲取指定index位置的元素

4 int indexOf(Object obj) 返回obj在集合中首次出現(xiàn)的位置

5 int lastIndexOf(Object obj) 返回obj在當(dāng)前集合中末次出現(xiàn)的位置

6 Object remove(int index) 移除指定index位置的元素,并返回此元素

7 Object set(int index, Object ele) 設(shè)置指定index位置的元素為ele

8 List subList(int fromIndex, int toIndex) 返回從fromIndex到toIndex 位置的子集合*/

List接口方法

packagecom.lzh.java1;importorg.junit.Test;importjava.util.ArrayList;importjava.util.Arrays;importjava.util.List;public classListMethodTest {

@Testpublic voidtest1(){

ArrayList list1= newArrayList();for(int i = 0;i < 5;i++){

list1.add("list"+i);

}//1 void add(int index, Object ele) 在index位置插入ele元素

list1.add(0,"第一個(gè)元素");

System.out.println(list1);//[第一個(gè)元素, list0, list1, list2, list3, list4]//2 boolean addAll(int index, Collection eles) 從index位置開始將eles中 的所有元素添加進(jìn)來

List list2 = Arrays.asList(1,2,3);

list1.addAll(list2);

System.out.println(list1.size());//9//3 Object get(int index) 獲取指定index位置的元素

System.out.println(list1.get(0)); //第一個(gè)元素

System.out.println(list2.get(0)); //0//4 int indexOf(Object obj) 返回obj在集合中首次出現(xiàn)的位置,如果不存在返回 -1

int index = list1.indexOf(3);

System.out.println(index);//8

}

@Testpublic voidtest2(){

ArrayList list= newArrayList();

List l= Arrays.asList("a",1,5,3);

list.addAll(l);

list.add(3);//System.out.println(list);//5 int lastIndexOf(Object obj) 返回obj在當(dāng)前集合中末次出現(xiàn)的位置

int index = list.lastIndexOf(3);

System.out.println(index);//4//6 Object remove(int index) 移除指定index位置的元素,并返回此元素

Object remove = list.remove(0);

System.out.println(remove);//a

System.out.println(list); //[1, 5, 3, 3]//7 Object set(int index, Object ele) 設(shè)置指定index位置的元素為ele

Object p = list.set(1, "hello");

System.out.println(p);//5

System.out.println(list); //[1, hello, 3, 3]//8 List subList(int fromIndex, int toIndex) 返回從fromIndex到toIndex 位置的子集合

List newList = list.subList(2,4);

System.out.println(newList);//[3,3]

}

}

List接口方法測試

8 - Collection子接口之二:Set接口

/*

set接口:

1 Set接口是Collection的子接口,set接口沒有提供額外的方法(用的都是Collection聲明的方法)

2 Set 集合不允許包含相同的元素,如果試把兩個(gè)相同的元素加入同一個(gè) Set 集合中,則添加操作失敗。

3 Set 判斷兩個(gè)對象是否相同不是使用 == 運(yùn)算符,而是根據(jù)equals() 方法

4 存儲數(shù)據(jù)特點(diǎn):無序、不可重復(fù)

*/

packagecom.lzh.java2;importorg.junit.Test;import java.util.*;/*1 Set接口框架:

/----Set接口:存儲無序、不可重復(fù)的數(shù)據(jù) -->高中講的"集合"

/----HashSet:作為Set接口的主要實(shí)現(xiàn)類,線程不安全的,可以存儲null值

/----LinkedHashSet:Linked(鏈表),作為HashSet的子類,遍歷其內(nèi)部數(shù)據(jù)時(shí),可以按照添加的順序遍歷

/----TreeSet:可以按照添加對象的指定屬性,進(jìn)行排序,要求:添加的數(shù)據(jù)是相同類的對象

①兩種排序方式:自然排序(comparable) 和 定制排序(comparator)

②自然排序中,比較兩個(gè)對象是否相同的標(biāo)準(zhǔn)為:compareTo() 返回0,不再是equals()

③定制排序中,比較兩個(gè)對象是否相同的標(biāo)準(zhǔn)為:compare() 返回0,不再是equals()

要求:

1 向Set中添加的數(shù)據(jù),其所在的類一定要重寫 hashCode() 和 equals()

2 重寫的 hashCode() 和 equals() 盡可能保持一致性:相等的對象必須具有相等的散列表

2 理解Set接口存儲數(shù)據(jù):無序、不可重復(fù)性。

① 無序性:不等于隨機(jī)性。存儲的數(shù)據(jù)在底層數(shù)組中并非按照數(shù)組索引的順序添加,而是根據(jù)數(shù)據(jù)的哈希值進(jìn)行存儲

② 不可重復(fù):保證添加的元素按照equals()判斷時(shí),不能返回true。即相同的元素只能添加一個(gè)

3 添加元素的過程:以HashSet為例

我們向HashSet中添加元素a,首先調(diào)用元素a所在類的HashCode()方法,計(jì)算元素a的哈希值,此哈希值接著通過某種算法計(jì)算出在HashSet底層數(shù)組中存放的位置(索引),

判斷數(shù)組此位置上是否已經(jīng)有元素:

如果此位置上沒有其他元素,則元素a添加成功。 --> 情況1

如果此位置上沒有其他元素b(或以鏈表形式存在的多個(gè)元素),則比較元素a與元素b的hash值:

如果hash值不相同,則元素a添加成功。 --> 情況2

如果hash值相同,進(jìn)而需要調(diào)用元素a所在類的equals()方法:

equals()返回true,元素a添加失敗

equals()返回false,則元素a添加成功 --> 情況3

對于添加成功的情況2和情況3而言:元素a 與已經(jīng)存在指定索引位置上數(shù)據(jù)已鏈表的方式存儲

JDK 7:元素a放到數(shù)組中,指向原來的元素

JDK 8:原來的元素在數(shù)組中,指向元素a

總結(jié):HashSet底層:數(shù)組+鏈表的結(jié)構(gòu)*/

public classSetTest {

@Testpublic voidtest1(){

Set set= newHashSet();for(int i = 0;i < 5;i++){

set.add("list"+i); //有序存儲

}

set.add(new User("howie",21));

set.add(new User("howie",21));

Iterator iterator=set.iterator();while(iterator.hasNext()){

System.out.println(iterator.next());//無序輸出

}

}//LinkedHashSet遍歷內(nèi)部數(shù)據(jù)//LinkedHashSet作為HashSet的子類,在添加數(shù)據(jù)的同時(shí),每個(gè)數(shù)據(jù)還維護(hù)了兩個(gè)引用,記錄此數(shù)據(jù)前一個(gè)數(shù)據(jù)和后一個(gè)數(shù)據(jù)//優(yōu)點(diǎn):對于頻繁遍歷操作,LinkedHashSet效率高于HashSet

@Testpublic voidtest2(){

Set set= newLinkedHashSet();for(int i = 0;i < 5;i++){

set.add("list"+i); //有序存儲

}

Iterator iterator=set.iterator();while(iterator.hasNext()){

System.out.println(iterator.next());//有序輸出

}

}

}classUser{privateString name;private intage;publicUser(){}public User(String name,intage){this.name =name;this.age =age;

}

@OverridepublicString toString() {return "User{" +

"name='" + name + '\'' +

", age=" + age +

'}';

}

@Overridepublic booleanequals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;

User user=(User) o;return age == user.age &&Objects.equals(name, user.name);

}

@Overridepublic inthashCode() {returnObjects.hash(name, age);

}

}

Set接口框架

1-Set實(shí)現(xiàn)類之一:HashSet

/*

HashSet介紹:

1HashSet 是 Set 接口的典型實(shí)現(xiàn),大多數(shù)時(shí)候使用 Set 集合時(shí)都使用這個(gè)實(shí)現(xiàn)類。

2 HashSet 按 Hash 算法來存儲集合中的元素,因此具有很好的存取、查找、刪除 性能。

3 HashSet 具有以下特點(diǎn):

① 不能保證元素的排列順序

② HashSet 不是線程安全的

③ 集合元素可以是null

4 HashSet集合判斷兩個(gè)元素相等的標(biāo)準(zhǔn):兩個(gè)對象通過hashCode() 方法比較相 等,并且兩個(gè)對象的 equals() 方法返回值也相等。

5對于存放在Set容器中的對象,對應(yīng)的類一定要重寫equals()和hashCode(Object obj)方法,以實(shí)現(xiàn)對象相等規(guī)則。即:“相等的對象必須具有相等的散列碼”

6 向HashSet中添加元素的過程:

①當(dāng)向 HashSet 集合中存入一個(gè)元素時(shí),HashSet 會(huì)調(diào)用該對象的 hashCode() 方法 來得到該對象的 hashCode 值,然后根據(jù) hashCode 值,通過某種散列函數(shù)決定該對象 在 HashSet 底層數(shù)組中的存儲位置。(這個(gè)散列函數(shù)會(huì)與底層數(shù)組的長度相計(jì)算得到在 數(shù)組中的下標(biāo),并且這種散列函數(shù)計(jì)算還盡可能保證能均勻存儲元素,越是散列分布, 該散列函數(shù)設(shè)計(jì)的越好)

②如果兩個(gè)元素的hashCode()值相等,會(huì)再繼續(xù)調(diào)用equals方法,如果equals方法結(jié)果 為true,添加失敗;如果為false,那么會(huì)保存該元素,但是該數(shù)組的位置已經(jīng)有元素了, 那么會(huì)通過鏈表的方式繼續(xù)鏈接。

7如果兩個(gè)元素的 equals() 方法返回 true,但它們的 hashCode() 返回值不相 等,hashSet 將會(huì)把它們存儲在不同的位置,但依然可以添加成功

*/

/*1 在程序運(yùn)行時(shí),同一個(gè)對象多次調(diào)用 hashCode() 方法應(yīng)該返回相同的值。

2 當(dāng)兩個(gè)對象的 equals() 方法比較返回 true 時(shí),這兩個(gè)對象的 hashCode() 方法的返回值也應(yīng)相等。

3 對象中用作 equals() 方法比較的 Field,都應(yīng)該用來計(jì)算 hashCode 值*/

重寫 hashCode() 方法的基本原則

/*以自定義的Customer類為例,何時(shí)需要重寫equals()?

1 當(dāng)一個(gè)類有自己特有的“邏輯相等”概念,當(dāng)改寫equals()的時(shí)候,總是 要改寫hashCode(),根據(jù)一個(gè)類的equals方法(改寫后),兩個(gè)截然不 同的實(shí)例有可能在邏輯上是相等的,但是,根據(jù)Object.hashCode()方法, 它們僅僅是兩個(gè)對象。

2 因此,違反了“相等的對象必須具有相等的散列碼”。

3 結(jié)論:復(fù)寫equals方法的時(shí)候一般都需要同時(shí)復(fù)寫hashCode方法。通 常參與計(jì)算hashCode的對象的屬性也應(yīng)該參與到equals()中進(jìn)行計(jì)算。*/

重寫 equals() 方法的基本原則

2-Set實(shí)現(xiàn)類之二:LinkedHashSet

/*

LinkedHashSet介紹:

1 LinkedHashSet 是 HashSet 的子類

2 LinkedHashSet 根據(jù)元素的 hashCode 值來決定元素的存儲位置, 但它同時(shí)使用雙向鏈表維護(hù)元素的次序,這使得元素看起來是以插入 順序保存的。

3 LinkedHashSet插入性能略低于HashSet,但在迭代訪問 Set 里的全 部元素時(shí)有很好的性能。

4 LinkedHashSet 不允許集合元素重復(fù)

*/

底層結(jié)構(gòu)

3-Set實(shí)現(xiàn)類之三:TreeSet

1 TreeSet 是SortedSet 接口的實(shí)現(xiàn)類,TreeSet 可以確保集合元素處于排序狀態(tài)。

2 TreeSet底層使用紅黑樹結(jié)構(gòu)存儲數(shù)據(jù)

3新增的方法如下: (了解)

1 Comparator comparator()

2 Object first() ?Object last()

3 Object lower(Object e)

4 Object higher(Object e)

5 SortedSet subSet(fromElement, toElement)

6 SortedSet headSet(toElement)

7 SortedSet tailSet(fromElement)

4 TreeSet 兩種排序方法:自然排序和定制排序。默認(rèn)情況下,TreeSet 采用自然排序

總結(jié)

以上是生活随笔為你收集整理的java 集合 接口_Java集合之Collection接口的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。