Collection

一、集合概述;

集合類,或者叫集合框架;

數據多了,封裝爲對象;對象多了,封裝爲集合;

對象多了,可以存儲於數組,但是數組是固定長度的,集合是可變長度的;而且數組中只能同類類型數據,集合不限類型;

集合中的對象,被稱爲元素;

 

集合的特點是用於存儲對象,集合的長度是可變的,集合可以存儲不同類型的對象;

集合的作用就相當於是一個封裝對象的容器;

容器分很多中,容器的共性不斷的抽取就產生了體系,這個體系就叫做集合框架;

在一個體系中通過最頂層來認識共同基本的功能,再讓底層子類進行功能的實現和擴展並加以利用;

接口的方法有了,下面就要建立其子類對象來對其進行使用;

 

集合框架是工具包的成員,Java.util.中的Collection成員;Collection是這個工具包的接口;

 

Collection接口有兩個常見的子接口,一個是List,一個是Set;

List接口中常見的子類有:ArrayList,LinkedList,Vector;

Set接口中常見的子類有HashSet,TreeSet;

 

爲什麼會出現這麼多的容器呢?因爲每一個容器對數據的存儲方式都有不同,這個存儲方式稱之爲:數據結構;

數據在內存中的構成情況,存儲方式稱爲數據結構,所以他們的特點不一樣,所以就要單獨的劃分;

 

二:Collection接口中的共性方法;

 

集合作爲一個容器,應該有的功能有增刪改查;

接口的使用是,先實現子類,然後建立子類對象即ok;

 

 

ArrayList al = new ArrayList ();

1、添加元素:

al.add(“abc”);   字符串也是對象;

集合中存在的不可能是集合實體;否則還要讓實體移位置;

集合和數組一樣,裏面存放的都是地址值;

 

注意:add方法的參數類型是Object,以便於接受任意類型對象;

集合中存儲的都是對象的引用(地址);

al.size(al);獲取集合的長度;

sop(al)

添加完成後直接打印集合的聲明變量,結果是這個集合裏面的所有元素,不是哈希值;

 

2、刪除元素:

al.remove();刪除指定元素;

al.clear();清空集合;

3、判斷元素:

al.contains();

al.isEmpty();

 

al1.retainAll(al2);取交集,al1中只會保留和al2中相同的元素,會對原集合進行改變;先把原集合清空,然後添加相同的元素,如果沒有相同的元素,則原集合爲空;

 

al1.removeAll(al2);指去掉與給定集合中相同的元素;

 

還有addAll等都是對相同的元素進行操作;

 

3、取出元素:(迭代器Iterator())

通過取出元素後對元素進行操作,直接打印集合沒有什麼實際意義;

Iterator it = al.iterator();  獲取迭代器,用於去處集合中的元素;

該表達式返回的是一個對象,然後可以通過對象去調用其對應的類的內部方法;

(這就是單例設計模式的一個例子;)完成這步之後就用it去調用方法了。

但問題的關鍵是接口不是都是抽象沒有方法不,這個比較疑惑;是在子類中實現了該方法,只不過用接口去聲明類型,避免引入更多的變量,也是一樣的;最後引入的還是子類實現的內部類的方法

it .hasNext();判斷是否有元素;it.next();獲取下一個元素;

 

什麼是迭代器呢?

其實就是集合的取出元素的方式;

迭代動作;

 

每個容器(集合)裏面都有自己的存取方式,因爲每個容器的數據結構不一樣,所以他們存取的動作細節以及存取的方式也有可能不一樣;

 

因爲取出的工作沒有像添加那麼的簡單,比如還需要判斷等,所以取出不能用一個方法判斷完,雖然取出的動作細節都不一樣,即所以就把取出功能封裝成一個類,這個類就定義到了集合的內部(內部類更方便操作);因爲都是有共性的內容,判斷和取出,,所以就可以將這些進行共性抽取,而這些內部類都是符合一個規則,該規則是Iterator。如何獲取集合的取出對象呢?通過一個對外提供的方法Iterator();

其實就是說,在集合的內部,用一個內部類實現了一個取出元素的接口;以後可以嘗試把這個方法自己寫出來;

 

寫法上:

要迭代所有的元素,用for循環比用while循環更加節約內存;

for(Iterator  it = al.iterator();it.hasNext();)

                   it.next();

 

 

三、Collection兩個常見子接口List和Set的特點:

List接口:這個集合小體系的特點在於集合裏面的元素是有序的,並且元素可以重複;因爲該集合體繫有索引;

Set接口:集合元素是無序的,元素不可以重複,集合當中沒有索引;

(一)List接口特有的共性方法:

1、凡是可以操作腳標的方法都是該體系特有的方法;增、刪、改、查;

增:

void add(int index, E element) 

boolean addAll(int index, Collection<?extends E> c) 

E remove(int index) 

E set(int index, E element)

E get(int index)

List<E> subList(int fromIndex, inttoIndex) (其實這個可以通過get方法循環即可;)

ListIterator<E> listIterator(intindex)

 

注意,但凡操作腳標的都是數組原理;

 

獲取對象的index位置;

int indexOf(Object o) 

 

int lastIndexOf(Object o)

 

獲取子列表:

List<E> subList(int fromIndex, inttoIndex)

 

列表迭代器

ListIterator<E> listIterator(intindex)

 

在迭代過程中,準備進行其他的操作,如添加或者刪除元素;

Iterator it = al.iterator();

it.remove;移除迭代出來的動作;

 

List集合特有的迭代器,ListIterator是Iterator的子接口;

在迭代時,不可以通過集合對象的方法操作集合中的元素,因爲會發生併發修改異常;

所以只能在迭代時,只能用迭代器方法操作元素,可是Iterator方法有限的,只能進行判斷,取出和刪除的操作;如果想要其他的操作如修改,添加等,就需要使用其子接口,ListIterator,

該接口只能通過List集合的ListIterator方法獲取;

 

ListIteratorli = al.ListIterator();

voidadd(E e)  在迭代的後面的添加給定的元素;

voidset(E e)  把迭代的元素改爲給定元素;

 

只有List集合中的迭代器纔有這種在遍歷過程中的增刪改查功能;因爲List是有腳標的;

 

booleanhasNext()  指針後面有沒有元素;

booleanhasPrevious()  指針前面有沒有元素;

E previous() 往前取元素;到這取,逆向遍歷;

 

2、List常見的三個子類對象:是因爲底層數據結構不一樣,而單獨封爲實體的;

ArrayList    底層的數據結構使用的是數組結構;特點在於查詢速度很快,因爲有腳標;加入和刪除元素時速度非常慢,元素越多越明顯;

LinkedList                   底層使用的是鏈表數據結構;列表查詢非常慢,因爲只有相鄰的元素纔有關係;但是增刪比較塊;因爲查詢必須要從第一個開始查起;

   Vector     底層是數組數據結構,功能和ArrayList一模一樣;它出現的時候集合框架還不存在呢?

         vector與ArrayList的區別是ArrayList線程是不同步的,Vector線程是同步的;一般用ArrayList,效率高,Vector增刪查詢都非常慢;替代了Vector,多線程中可以對ArrayList進行加鎖;

         Java的集合框架中會有一個專門加鎖的功能;

         ArrayList的默認容量是10的空列表,當元素增加後,他會new一個新的數組,長度增加百分之50的延長,然後把原來的數組複製過來即可

         Vector是百分之百的延長,比較浪費空間;基本淘汰了;

 

Vector裏的唯一的特有取出數據方法——枚舉,其他都被ArrayList取代了;

        

Enumerationen =  v.elements();

while(en.hasMoreElements())

         en.nextElement();可以枚舉所有的元素出來;

 

發現枚舉和迭代器很像;其實枚舉和迭代是一樣的;因爲枚舉的名稱以及方法的名稱都過長,所以被迭代器取代了;枚舉和Vector都是1.0版本的,以後版本的都是用迭代器了,不用枚舉了;

 

LinkedList鏈表結構的List,所使用頻率不是特別高;他的特有方法有:

 

addFirst();

addLast();

 

getFirst();

getLast();

獲取元素,但不刪除元素;如果集合中沒有元素,會出現NoSuchElementException

removeFirst();——peekFirst

removeLast();——pollFirst

也可以獲取元素,但是元素被刪除;如果集合中沒有元素,會出現NoSuchElementException

 

在JDK1.6版本中,出現了替代方法;以後就用這個,不用之前的方法了;

booleanofferFirst(E e)

         

 boolean offerLast(E e)

        

EpeekFirst()

          獲取但不移除此列表的第一個元素;如果此列表爲空,則返回 null。

 E peekLast()

          獲取但不移除此列表的最後一個元素;如果此列表爲空,則返回 null。

EpollFirst()

          獲取並移除此列表的第一個元素;如果此列表爲空,則返回 null。

 E pollLast()

                 獲取並移除此列表的最後一個元素;如果此列表爲空,則返回 null。 

 

練習1:使用LiskedList模擬一個堆棧或者隊列數據結構;

 

堆棧的數據結構的特點:先進後出;如同一個杯子;

隊列的數據結構的特點:先進先出;如同一個水管;

        

要先封裝起來,先把描述和功能封裝起來,然後對外提供一個最簡單的訪問方式即可;

 

這個練習要求必須會;

 

練習2:去除ArrayList集合中的重複元素;

用it.next()在循環當中只能寫一次,如果寫多次就極有可能出現腳標異常;

即在迭代時循環中next調用一次,就要hasNext判斷一次;

不能同時在一個語句中

 

練習3:將自定義對象作爲元素存在ArrayList集合中,並去除重複元素;

比如,存人對象,同姓名,同年齡,視爲同一個人,爲重複元素;

(1)描述人,將數據封裝進入對象;

(2)定義容器,存人;

(3)取出

 

List集合判斷元素是否相同,依據的元素的equals方法;contains,removed底層都是依賴的這個方法,ArrayList和LinkedList集合底層的數據結構的方法依賴的都是這個;

其他的集合和這個不一樣;

 

涉及的增刪操作比較頻繁用LinkedList集合

涉及的查詢操作比較頻繁用ArrayList集合

當然兩者都可以用,一般實在不好找,就用ArrayList;

 

 

(二)Set集合

元素是無序的,即存入和取出的順序不一定一致,元素不可以重複;

Set集合的功能和Collection集合功能是一致的,因爲都沒有腳標;

 

常見的子類:

HashSet集合:底層數據結構是哈希表; TreeSet集合

1、HashSet集合

 

哈希值,取出來的是按照集合裏面的哈希值的順序來的;

在哈希表裏,如果哈希值重複的時候,他還有另外一個調取方式,即對象是否是同一個對象;如果哈希值相同,就比較兩個是不是一個對象;如果不是就在此位置上順延;

如果哈希值不同,就直接按哈希值直接保存;

 

演示:

往hashSet集合中存入自定義對象,姓名和年齡相同爲同一個人,重複元素;

 

Set中取出元素就只有一種方式,即迭代器;

Set集合;可以保證唯一性;因爲不可重複性;

 

按照條件來設定哈希值;來保證Hashcode的唯一;

 

HashSet是如何保證元素的唯一性的呢?

 

是通過元素的兩個方法,hashcode和equals來完成的,如果元素的hashcode值相同,纔會判斷equals是否爲true,如果元素的hashcode不同,則equals爲false;

 

當我們要把對象存放在HashSet集合當中的時候,我們一般都要重寫成我們需要的hashcode和equals方法;而且這些方法並不是我們自己調用的,而是底層內部調用的,集合把他的調用方法給封裝了,我們不知道;

一般開發中,只要我們把數據往集合中保存,我們都最好都要重寫上面兩個函數;儘量保證hashcode的唯一性,這樣纔會主動進行比較是否相同;

 

如何查詢是否包含,以及刪除元素:

 

注意:對於判斷元素是否存在以及刪除等操作,依賴的方法都是元素的hashcode和equals方法;先判斷hashcode,相等的情況再比較equals方法;

 

 

ArrayList集合裏的方法操作只依賴equals方法;

 

2、TreeSet集合

set:無序,不可重複元素;

HashSet集合:底層數據結構是哈希表; 線程是非同步的;因爲數據結構不一樣,保證元素唯一性的方式也不一樣;HashSet保證元素的唯一性的原理是:判斷元素的hashcode是否相同,如果相同,還會繼續判斷元素的equals方法,是否爲true;

 

TreeSet集合:特點是,可以對set集合中的元素進行排序;是按照自然順序來排序的;

                            底層數據結構是二叉樹;保證元素唯一性的依據是compareto 方法return 0;

                            其所有的操作也都是依賴這個方法進行操作,如判斷包含,刪除等;

 

演示:存自定義數據演示該集合

 

需求:往TreeSet集合中存儲自定義對象學生,想按照學生的年齡進行排序;

 

TreeSet集合往裏面存放的元素必須要具有比較性才行;否則會拋出錯誤;

 

因爲要排序,並且該集合不能重複,所以只要判斷是相同對象,就不會進入集合;

 

注意:排序時,當主要條件相同時,一定要判斷次要條件是否相同;

 

TreeSet底層的數據結構是:

 

排序無非就是互相比較,如果元素太多,就會導致效率非常慢;所以爲了優化效率,TreeSet優化了數組的效率,TreeSet用了一個比較特殊的數據結構來做這個事情;

 

二叉樹數據結構,可以減少比較次數;而且,如果元素比較多的情況,他比較到最後,會自動取折中值來進行比較;這樣就可以提高效率;

 

取值都是按照默認順序,從小到大來取;二叉樹的數據結構都是從左邊最小的數據往上開始取值;

 

如果要降序排列,可以把重寫的compareTo中返回值中1改爲-1等;

 

TreeSet排序只看compare的比較結果,不看你是用什麼方法比的;

 

可以讓TreeSet取出數據的方式按照存放順序取,只需要重寫比較方法,返回1即可,逆序也一樣;

 

TreeSet排序的第一種方式,讓元素自身具備比較性,元素需要實現comparable接口,覆蓋comparato方法,這種方式也稱爲元素的自然排序,或者叫做默認排序;

 

元素一定義完,就具備了比較性了,具有默認順序了;

 

TreeSet的的第二種排序方式:

當元素自身不具備比較性,或者具備的比較性不是所需要的;這時就需要讓集合自身具備比較性;在集合初始化時,就有了比較方式;

 

當元素自身不具備比較性,或者具備的比較性不是所需要的,這是需要讓容器自身具備比較性,定義了比較器,將比較器對象作爲參數傳遞給TreeSet集合的構造函數;

 

當兩種排序都存在時,以比較器爲主;

 

定義一個類,實現comparator接口,覆蓋compare方法

 

二叉樹都是以判斷return是否爲0,來比較是否相等;

 

一般,比較器的方法用的比較多;功能擴展就直接實現需要的接口即可;所以開發時候一定都把接口弄出來,以後直接升級實現接口就搞定了

 

練習:按照字符串長度排序

 

字符串本身具備比較性,但是他的比較方式不是所需要的,這時就只能使用比較器;

 

當然也可以把封裝的比較器用匿名內部類做也行;

 

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