一区二区三区日韩精品-日韩经典一区二区三区-五月激情综合丁香婷婷-欧美精品中文字幕专区

分享

徐葳【2019版最新】40小時(shí)掌握J(rèn)ava語言之07集合

 大數(shù)據(jù)徐葳 2019-03-30

1章:集合類

1.1 集合概述

下面我們來學(xué)習(xí)一個(gè)比較重要的類,集合類,這個(gè)在工作中也是經(jīng)常使用的。

數(shù)據(jù)多了需要存儲(chǔ),比如數(shù)組,而對(duì)象多了也需要存儲(chǔ)。

數(shù)組能存對(duì)象嗎?可以的。

到底會(huì)產(chǎn)生多少對(duì)象,是不確定的,所以數(shù)組就沒法存儲(chǔ)了。

這個(gè)時(shí)候出現(xiàn)了集合類,

面向?qū)ο笳Z言對(duì)事物的體現(xiàn)都是以對(duì)象的形式,所以為了方便對(duì)多個(gè)對(duì)象的操作,就對(duì)對(duì)象進(jìn)行存儲(chǔ),集合就是存儲(chǔ)對(duì)象最常用的一種方式。

集合和數(shù)組的特點(diǎn)

相同點(diǎn):

集合和數(shù)組都是容器

不同點(diǎn):

數(shù)組可以存儲(chǔ)基本數(shù)據(jù)類型和對(duì)象,長(zhǎng)度是固定的;

集合長(zhǎng)度是可變的,但是集合只能存儲(chǔ)對(duì)象。

如圖1.1所示。

從下向上一步一步抽取到最上面的一層。Collection,這是一個(gè)接口

假設(shè)左邊的是一種裝水的容器,右邊的也是,抽取到最后這些容器都是可以裝水的,這個(gè)就是共性。

Collection下面有list,還有set,

這兩個(gè)下面還有很多具體的類,我們后面會(huì)具體的講解。在這就不寫了。

1.1 集合體系結(jié)構(gòu)

想要學(xué)習(xí)和使用這個(gè)體系,一個(gè)快速有效的方法就是,查閱該體系中頂層的類或者接口中的方法,了解該體系的共性基本功能,建立最子類的對(duì)象進(jìn)行功能的使用。

那也就是說我要首先去學(xué)習(xí)Collection接口中的功能,這里面的東西學(xué)完之后就掌握一半了,剩下的就是具體子類之間的一些區(qū)別了。

詳細(xì)一些的集合體系結(jié)構(gòu)圖如圖1.2所示。

java集合類

1.2 集合體系結(jié)構(gòu)

1.2 Collection功能

API文檔中看一下collection中都有哪些方法,如圖1.3所示。

這個(gè)接口是在java.util包中,以后要用的時(shí)候就需要時(shí)就需要用import 導(dǎo)入這個(gè)包中的類了,咱們前面學(xué)習(xí)的一些類都會(huì)java.lang包里面的,java.lang包里面的類在使用的時(shí)候是不需要導(dǎo)包的。

1.3 集合中的方法

大致看一下API文檔中列出來的集合中的所有方法。

創(chuàng)建集合對(duì)象:

先導(dǎo)包,創(chuàng)建對(duì)象。找一個(gè)子類的實(shí)現(xiàn)類,Arraylist

操作代碼如圖1.4所示。

1.4 集合操作

下面演示一下Collection中帶All的方法

代碼如圖1.5所示。

1.5 Collection的操作

1.3迭代器

前面介紹了一下Collection里面的常見方法

還有一個(gè)比較重要的方法,是iterator,叫迭代,

其實(shí)可以把迭代理解為順序讀取,它的返回值比較特殊,如圖1.6所示

1.6 迭代器

迭代器里面的方法如圖1.7所示。

1.7 迭代器里面的方法

先寫一個(gè)簡(jiǎn)單的例子,獲取一下集合中的元素

寫個(gè)例子,先創(chuàng)建ArrarList,再添加元素,調(diào)用iterator方法

代碼如圖1.8所示。

這里面直接使用next取值是有問題的,可能會(huì)報(bào)錯(cuò)。

1.8 迭代器操作

下面這種寫法就可以了。

如圖1.9 所示。

1.9 迭代器操作

注意了:

1:容器都有取出方式

2:容器的取值方式都符合某一規(guī)則

3:每個(gè)容器自身都有自己的數(shù)據(jù)結(jié)構(gòu),但是取出的規(guī)則都一致。

這樣我們可以用統(tǒng)一規(guī)則來操作所有容器的取出。

例如,商場(chǎng)外面的投幣機(jī),投個(gè)幣,就可以操作搖桿進(jìn)行抓取,

可以把這個(gè)容器認(rèn)為是一個(gè)集合,里面都是布娃娃,這些布娃娃可以認(rèn)為是集合里面的元素,這個(gè)夾子,就是迭代器。如圖1.10所示。

1.10 布娃娃機(jī)

在集合中,取出元素的格式是固定的。

只要是Collection集合體系,迭代器就是通用去除方式。

1.4 集合練習(xí)-存儲(chǔ)自定義對(duì)象

存儲(chǔ)自定義Person對(duì)象,有姓名、年齡等基本屬性

將對(duì)象存儲(chǔ)到集合中,并取出,獲取其姓名或者年齡。

首先對(duì)該對(duì)象進(jìn)行描述,如圖1.11所示。

1.11 Person類描述

下面定義一個(gè)集合并且添加元素,使用iterator方法可以打印出集合中的元素,但是打印的卻是元素的內(nèi)存地址值,如圖1.12所示。

1.12 操作集合

想要打印元素的名稱,需要調(diào)用getName方法,但是報(bào)錯(cuò),提示getName不在Object類中。那說明it.next方法的返回值是對(duì)象,如圖1.13所示。

1.13 代碼

下面開始分析

add(Object obj);// 可以接收任意類型對(duì)象,但是任意類型的對(duì)象都被提升為了Object。所以在取出元素時(shí),取出來的也是Object

那如果想使用Person對(duì)象中的屬性的時(shí)候,就需要強(qiáng)轉(zhuǎn)了,看這個(gè)例子,如圖1.14所示。

1.14 強(qiáng)轉(zhuǎn)

但是會(huì)發(fā)現(xiàn)代碼執(zhí)行報(bào)錯(cuò)了,因?yàn)樵谝粋€(gè)while循環(huán)中不應(yīng)該多次調(diào)用next方法,每一次調(diào)用next方法都是取出一個(gè)新元素,所以代碼需要調(diào)整一下,如圖1.15所示。這樣改造才行。

1.15 強(qiáng)制轉(zhuǎn)換

其實(shí)list里面存儲(chǔ)的都是對(duì)象的內(nèi)存地址,如圖1.16所示。

1.16 list內(nèi)存圖

注意:

Collection coll = new ArrayList();  //集合中存儲(chǔ)的都是對(duì)象引用。

Iterator it = coll.iterator();  //獲取迭代器后,迭代器中持有的也是元素的引用

1.5 集合框架中的常用接口

Collection接口有兩個(gè)子接口:

List(列表)Set(集合)

List:可存放重復(fù)元素(因?yàn)樵赜兴饕菢?biāo)),元素存取是有序的。

Set:不可以存放重復(fù)元素,元素存取是無序的。

2章:list詳解

2.1 List集合中常見的共性方法

看這個(gè)集合框架體系圖,如圖2.1所示。

2.1 集合框架體系圖

我們已經(jīng)搞定了collection接口,它下面有兩個(gè)小弟,ListSet

接下來就來學(xué)習(xí)一下list接口,看下API中的介紹。

Collection

   |--List:該容器中的元素是有序的(存儲(chǔ)的順序和取出的順序一致)

該容器中的元素都有索引(角標(biāo)),該集合可以存儲(chǔ)重復(fù)的元素。

下面學(xué)習(xí)一下list集合中常見的共性方法。

因?yàn)?/span>list接口繼承了collection,所以主需要介紹list中特有的方法就可以了。

List的子類還使用Arraylist。

添加元素:add

刪除元素:remove

修改元素:set

獲取元素:get、indexOfsubList

代碼實(shí)現(xiàn)如圖2.2所示。

2.2 List的使用

針對(duì)List我們就先講這么多常用的方法。

2.2 List集合子類對(duì)象的特點(diǎn)

下面學(xué)習(xí)下list集合中子類對(duì)象的特點(diǎn)。

List下面一共有3個(gè)子類,有一個(gè)已經(jīng)不常用了,這3個(gè)最主要的區(qū)別是因?yàn)閿?shù)據(jù)結(jié)構(gòu)不一樣。

List:有序,可重復(fù),有索引

| --Vector:底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組結(jié)構(gòu)。jdk1.0版本。線程安全的。無論增刪還是查詢都非常慢。

| --ArrayList:底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組結(jié)構(gòu)。線程不安全的。所以ArrayList的出現(xiàn)替代了Vector,但是查詢的速度很快。

| --LinkedList:底層是鏈表數(shù)據(jù)結(jié)構(gòu)。線程不安全的,同時(shí)對(duì)元算的增刪操作效率很高 。

Arraylist中的方法和list中的基本一樣,在這我們就不說了。

注意:鏈表結(jié)構(gòu)是這樣的。讓后一個(gè)元素記住前一個(gè)元素的地址。

數(shù)組和鏈表的區(qū)別:

當(dāng)向數(shù)組中插入一個(gè)元素的時(shí)候,插入位置后面的元素都要往后移一位。元素越多越慢,如圖2.3所示。

2.3 數(shù)組結(jié)構(gòu)

如果是鏈表的話,插入一個(gè)新元素,只需要讓插入的元素記住前一個(gè)元素的位置,后一個(gè)元素記住插入元素的位置即可,非常簡(jiǎn)單快速。如圖2.4所示。

刪除也特別簡(jiǎn)單,只需要讓K記住A即可。中間的元素就刪掉了。

2.4 鏈表結(jié)構(gòu)

總結(jié):

鏈表:增刪快,查詢慢

數(shù)組:增刪慢,查詢快

Arraylist:查詢快

Linkedlist:增刪快

Vector:查詢和增刪都特別慢,但是線程安全。

在這發(fā)現(xiàn)ArraylistVector都是數(shù)組結(jié)構(gòu)的,那數(shù)組怎么實(shí)現(xiàn)長(zhǎng)度可變的存儲(chǔ)呢?

它們內(nèi)部封裝了一個(gè)默認(rèn)長(zhǎng)度為10的數(shù)組。當(dāng)超出長(zhǎng)度時(shí),集合內(nèi)部會(huì)自動(dòng)生成一個(gè)新的數(shù)組。將原數(shù)組中的元素復(fù)制到新數(shù)組中,再將新元素添加到新數(shù)組中。

新數(shù)組到底有多大呢?

ArrayList 50% 延長(zhǎng)

Vector 100% 延長(zhǎng)

2.3 List集合子類-LinkedList

下面詳細(xì)講一下下list中的linkedlist

鏈表的特有方法,是對(duì)頭尾元素進(jìn)行操作,看api文檔。

1. 在鏈表頭尾添加元素

addFirst、addLast

jdk1.6以后用這兩個(gè)方法替代 offerFirstofferLast

2. 獲取集合中的元素,集合的長(zhǎng)度不變

注意:如果集合中沒有元素,那么該方法會(huì)發(fā)生異常NoSuchElementException

getFirstgetLast

jdk1.6以后用這兩個(gè)方法替代 peekFirst、peekLast,如果集合中沒有元素,該方法不會(huì)拋異常,會(huì)返回null

3. 獲取集合中的元素,但是該元素會(huì)被從集合中刪除,集合的長(zhǎng)度會(huì)改變

removeFirst、removeLast

jdk1.6以后用這兩個(gè)方法替代 pollFirst、pollLast,如果集合中沒有元素,該方法不會(huì)拋異常,會(huì)返回null

代碼實(shí)現(xiàn)如圖2.5所示。

2.5 linkedlist操作

這個(gè)也能取到第一個(gè)元素,但是集合會(huì)變化。如圖2.6所示。

2.6 linkedlist操作

2.4 List集合子類-Vector

這個(gè)類已經(jīng)不常用了,一般只在多線程環(huán)境下使用。在這不做進(jìn)一步分析?;镜氖褂霉δ軈⒄?/span>Collection接口中的功能。

總結(jié)一下:

Collection

|--ArrayList

|--LinkedList

|--Vector

2.5 集合練習(xí)題-對(duì)字符串中的數(shù)值進(jìn)行排序

將字符串中的數(shù)值進(jìn)行排序后,生成一個(gè)新的字符串。

"39 -10 18 0 21 5"

思路:

1. 先把字符串中的數(shù)值取出

2. 存儲(chǔ)到int數(shù)組中

3. 對(duì)int數(shù)組排序

4. int數(shù)組變成字符串

代碼如圖2.7所示。

2.7 案例代碼

針對(duì)這些代碼可以提取出一些方法,不建議把代碼都寫到main方法中。

抽取后的代碼如圖2.8所示。

2.8 代碼抽取方法

3章:Set詳解

3.1 Set集合概述

講完了collection中的list之后,再說下collection下面的set接口

Collection

|--List:該容器中的元素是有序的(存儲(chǔ)的順序和取出的順序一致)

該容器中的元素都有索引(角標(biāo)),該集合可以存儲(chǔ)重復(fù)的元素。

|--SetSet集合中的元素是無序,不可以重復(fù)的,set接口的方法和collection中的方法一致,Set集合取出元素的方法只有迭代器。

應(yīng)用場(chǎng)景:假設(shè)要存儲(chǔ)的元素必須是唯一的,這個(gè)時(shí)候就可以使用Set集合。

Set中常用的是HashSetTreeSet。

3.2 HashSet

發(fā)現(xiàn)HashSet存入的順序和取出的順序不一樣,也就是說HashSet集合沒有按照添加的順序存儲(chǔ)。

如圖3.1所示。

3.1 hashSet操作

hashSet中不可以用有重復(fù)元素,如圖3.2所示。

3.2 hashSet操作

具體要使用list還是set要根據(jù)具體的業(yè)務(wù)需求,假設(shè)要存儲(chǔ)的元素必須是唯一的,這個(gè)時(shí)候就可以使用set集合。

下面具體看下HashSet的特點(diǎn):

HashSet:底層數(shù)據(jù)結(jié)構(gòu)是哈希表。

哈希表這種結(jié)構(gòu),其實(shí)就是對(duì)哈希值的存儲(chǔ)。線程不安全,存取速度快。

如圖3.3所示案例。

3.3 hashSet添加對(duì)象

存儲(chǔ)兩個(gè)相同姓名和年齡的人,如圖3.4所示。

3.4 hashSet添加對(duì)象

發(fā)現(xiàn)在HashSet中存儲(chǔ)了兩個(gè)相同的人,這是因?yàn)榕袛鄡蓚€(gè)人是否相等的依據(jù)HashSet是不知道的,所以需要我們自己定義。

所以就需要復(fù)寫Person類的equals方法,代碼如圖3.5所示。

3.5 復(fù)寫equals方法

再重新執(zhí)行一次HashSetDemo2,發(fā)現(xiàn),重復(fù)的元素還在。

那么說明代碼里面的比較重復(fù)功能沒有參考Person類的這個(gè)equals方法

在前面我們講ArrayList的時(shí)候,無論里面的containsremove都是參考的equals方法。

重新思考這問題,

他判斷元素唯一性的依據(jù)到底是什么呢?

HashSet:底層數(shù)據(jù)結(jié)構(gòu)是哈希表,哈希表這種結(jié)構(gòu),其實(shí)就是對(duì)哈希值的存儲(chǔ)。

HashSet在存儲(chǔ)時(shí)會(huì)計(jì)算元素的hash值,Object中有一個(gè)hashCode方法,如圖3.6所示。

3.6 hashCode方法

我們可以先把每個(gè)對(duì)象的hash值打印出來看一下,發(fā)現(xiàn)hash值都不同。如圖3.7所示。

3.7 hash

之前hashset是根據(jù)元素的hash值判斷元素是否重復(fù),

現(xiàn)在我們的需求是根據(jù)姓名和年齡判斷元素是否重復(fù)。

在這就需要把hashCode覆蓋了,直接返回一個(gè)1,

執(zhí)行之后發(fā)現(xiàn),打印的結(jié)果是4個(gè),并且發(fā)現(xiàn)equals方法也執(zhí)行了。

注意了,從這可以看出來的,現(xiàn)在4個(gè)元素的hash值都是1,但是也都同時(shí)存在了,這就說明hashset集合保證元素唯一性,依賴的是元素的hashCode方法和equals方法。如圖3.8所示。

3.8 hashset代碼

總結(jié)

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

通過equals方法和hashCode方法來保證元素的唯一性!

當(dāng)元素hash值值不同的時(shí)候,元素都有自己的獨(dú)立位置,不需要再判斷元素的equals方法。

當(dāng)元素的hash值相同時(shí),元素在hash表中位置相同,這時(shí)就需要再判斷一次元素的內(nèi)容是否相同,就需要調(diào)用元素的equals方法進(jìn)行一次比較,如果equals返回是true,那么視為是重復(fù)元素,只存儲(chǔ)一個(gè)。如果返回的是false,那么這兩個(gè)元素不是重復(fù)元素,會(huì)存儲(chǔ)在同一個(gè)hash值上。

為了建立自定義對(duì)象判斷元素是否重復(fù)的依據(jù),需要覆蓋hashCode方法和equals方法。而且最好依據(jù)對(duì)象的特有條件來建立hashCodeequals的實(shí)現(xiàn)。

注意了,其實(shí)這個(gè)時(shí)候直接把hashCode的值都返回1,效率是比較低的,因?yàn)檫@樣后來添加的所有元素都需要和之前添加的元素使用equals比較一次,因?yàn)樗麄兊?/span>hash值都相同。

所以我們實(shí)際應(yīng)該根據(jù)對(duì)象的特征返回不同的hashCode

在這我們要根據(jù)對(duì)象的姓名和年齡進(jìn)行比較,所以Person類中的hashCode可以這樣寫,如圖3.9所示。

3.9 hashCode方法

但是這樣的話如果張三的姓名的hashCode和李四的年齡相等,李四的姓名的hashCode和張三的年齡相等,這樣這兩個(gè)人使用我們自定義的hashCode返回值也是一樣的,為了避免這種特殊情況,我們就在age上乘以一個(gè)隨機(jī)數(shù),只要?jiǎng)e乘1就行。如圖3.10所示。

3.10 hashCode方法

一般我們自定義對(duì)象都會(huì)覆蓋兩個(gè)方法,hashCodeequals

hashcode :建立該對(duì)象自身特點(diǎn)定義的hash

equals:建立該對(duì)象內(nèi)容的判斷相同的依據(jù)

一般還會(huì)復(fù)寫toString

建立該對(duì)象對(duì)應(yīng)的字符串表現(xiàn)形式,因?yàn)槟J(rèn)toString打印的是對(duì)象的內(nèi)存地址值信息。

如圖3.11所示。

Person類中覆蓋toString方法。

3.11 覆蓋toString方法

3.3 Treeset

TreeSet

底層數(shù)據(jù)結(jié)構(gòu)是二叉樹結(jié)構(gòu)

可以對(duì)Set集合中的元素進(jìn)行排序。這種結(jié)構(gòu),可以提高排序性能。線程不安全。

看這個(gè)例子,打印的順序和存儲(chǔ)的順序不一致,但是打印的順序是按照字典順序排序的。

如圖3.12所示。

3.12 treeSet

3.4 LinkedHashset

鏈表結(jié)構(gòu),元素存入和取出的順序一致。是一個(gè)有序的集合。

代碼如圖3.13所示。

3.13 linkedHashSet操作

最后做一個(gè)總結(jié):

ArrayList:數(shù)組

LinkedList:鏈表

HashSet:哈希表

TreeSet:二叉樹

想要保證元素唯一,就用Set集合,不需要就使用List集合。

實(shí)在搞不清楚,默認(rèn)就使用ArrayList。

3.5 集合擴(kuò)展-Queue隊(duì)列

Queue就是一個(gè)先入先出(FIFO)的隊(duì)列。

針對(duì)一些需要進(jìn)行排隊(duì)的需求中,可以使用Queue隊(duì)列。

Queue接口與List、Set同一級(jí)別,都是繼承了Collection接口。

Queue中常用的一個(gè)子類是ConcurrentLinkedQueue :是基于鏈接節(jié)點(diǎn)的、線程安全的隊(duì)列,并發(fā)訪問不需要同步。所以這個(gè)子類隊(duì)列在多線程環(huán)境下使用也是安全的。

常用功能

offer      添加一個(gè)元素并返回true      如果隊(duì)列已滿,則返回false

poll       移除并返問隊(duì)列頭部的元素   如果隊(duì)列為空,則返回null

peek      返回隊(duì)列頭部的元素            如果隊(duì)列為空,則返回null

代碼實(shí)現(xiàn)如圖3.14所示。

注意:隊(duì)列的.size()是要遍歷一遍集合的,所以會(huì)很慢,所以盡量要避免用size而改用isEmpty().

3.14 queue隊(duì)列的使用

4章:泛型

4.1 泛型概述

下面學(xué)習(xí)一個(gè)新的技術(shù)泛型。

先寫一個(gè)list集合的案例,代碼如圖4.1所示。

4.1 list代碼

集合中什么對(duì)象都能放。

剛開始存的是字符串,現(xiàn)在我們存一些數(shù)字類型的數(shù)據(jù)。

這樣編譯沒問題,但是執(zhí)行的時(shí)候就會(huì)報(bào)錯(cuò),類型轉(zhuǎn)換異常,integer不能強(qiáng)轉(zhuǎn)為string。如圖4.2所示。

我們自己知道只能向里面?zhèn)髯址?,但是別人并不知道該存什么類型的數(shù)據(jù),這樣就容易出問題了。

4.2 轉(zhuǎn)換異常

集合中存儲(chǔ)了不同類型的對(duì)象,取出時(shí),容易在運(yùn)行時(shí)期發(fā)生classCastException類型轉(zhuǎn)換異常。

為了避免這個(gè)問題的發(fā)生,如果在存儲(chǔ)的時(shí)候就明確了集合要操作的數(shù)據(jù)類型,這樣取出就沒有問題了。

jdk1.5的時(shí)候提供了泛型機(jī)制,可以解決這個(gè)問題,可以使用<> 來明確元素的類型。

加上泛型之后,編譯的時(shí)候就報(bào)錯(cuò)了。如圖4.3所示

4.3 泛型

泛型的好處:

1. 將運(yùn)行時(shí)期出現(xiàn)的classCastException問題,轉(zhuǎn)移到了編譯時(shí)期。

2. 避免了強(qiáng)制轉(zhuǎn)換的麻煩。

加了泛型之后,就不需要強(qiáng)轉(zhuǎn)了。如圖4.4所示。

4.4 泛型的使用

之前看到文檔中的這種形式我們沒有詳細(xì)解釋。如圖4.5所示。這個(gè)其實(shí)就是ArrayList的泛型參數(shù)。

注意:泛型里面不能指定int之類的基本數(shù)據(jù)類型,只能指定對(duì)象,例如integer

4.5 文檔介紹

4.2 泛型在集合中的使用

泛型在集合中的使用,代碼如圖4.6所示。

4.6 泛型的應(yīng)用

4.3 泛型類

下面看一下泛型在程序設(shè)計(jì)中的體現(xiàn)。

看這個(gè)代碼,最開始的時(shí)候我有一個(gè)student對(duì)象,我用一個(gè)tool工具類來對(duì)這個(gè)學(xué)生進(jìn)行設(shè)置。

后期又來了一個(gè)woker對(duì)象,我還要對(duì)這個(gè)對(duì)象也寫一個(gè)工具類進(jìn)行操作。

這樣代碼的重復(fù)度太高了。代碼如圖4.7所示。

4.7 代碼

可以把student改為Object,這樣是利用了多態(tài)。如圖4.8所示。

4.8 代碼

這樣操作的時(shí)候獲取對(duì)象是需要強(qiáng)制轉(zhuǎn)換的,如圖4.9所示。

4.9 代碼

這樣會(huì)有一點(diǎn)風(fēng)險(xiǎn)性,我把worker對(duì)象傳進(jìn)去的話,這個(gè)時(shí)候編譯也是沒有問題的,但是執(zhí)行的時(shí)候就有問題了。如圖4.10 所示。

所以說現(xiàn)在的程序就沒有什么可控性了。

4.10 類型轉(zhuǎn)換異常

這個(gè)問題是可以使用泛型來解決的。使用泛型來解決安全隱患。

將泛型定義在類上,該泛型,在該類中有效。如圖4.11所示,在類上定義了一個(gè)泛型Q,注意,這個(gè)字母也可以寫其他的字母,沒有什么特殊要求。

4.11 泛型

用的時(shí)候這樣用,編譯運(yùn)行是沒有問題的,如圖4.12所示。

4.12 泛型的使用

如果我不小心傳了個(gè)worker。

這個(gè)時(shí)候,編譯就會(huì)報(bào)錯(cuò)了。如圖4.13所示。這樣就可以避免前面所說的類型轉(zhuǎn)換的安全隱患了。

4.13 泛型的使用

什么時(shí)候使用泛型類呢?

當(dāng)類要操作的引用數(shù)據(jù)類型不確定的時(shí)候可以這樣用,泛型定義在類上,該泛型作用于整個(gè)類。

4.4泛型方法

學(xué)完了泛型類之后,我們?cè)倏匆粋€(gè)小東西

這個(gè)代碼執(zhí)行是沒有問題的,如圖4.14所示。

4.14 泛型代碼

這個(gè)時(shí)候,創(chuàng)建tool的時(shí)候就需要指定泛型,后期就不能再傳遞其他類型的數(shù)據(jù)了。如圖4.15所示。

4.15 泛型代碼

那如果我想傳遞多種類型數(shù)據(jù)怎么辦呢?

當(dāng)泛型定義在類上,該泛型作用于整個(gè)類,當(dāng)該類建立對(duì)象時(shí),就明確了具體的類型,那么凡是使用了類上定義的泛型的方法,操作的類也就固定了。

需求:希望類中的方法可以操作任意類型而不受類中泛型的限制。

這個(gè)時(shí)候可以在方法上定義泛型,稱為泛型方法。

看這個(gè)例子:是沒問題的,字符串和數(shù)字都可以存儲(chǔ),如圖4.16所示。

4.16 泛型方法

靜態(tài)方法上不能使用類上定義的泛型,如圖4.17所示。

4.17 泛型代碼

當(dāng)類中定義static方法時(shí),靜態(tài)方法是不可以直接訪問類上的泛型,

因?yàn)轭惿系姆盒椭挥型ㄟ^建立對(duì)象才可以明確具體類型。

所以靜態(tài)方法如果操作的引用數(shù)據(jù)類型不確定,只能將泛型定義在方法上,

在靜態(tài)方法上定義泛型,必須定義在static關(guān)鍵字之后,如圖4.18所示。

4.18 靜態(tài)方法泛型

什么時(shí)候?qū)⒎盒投x在方法上呢?

當(dāng)方法中操作的應(yīng)用數(shù)據(jù)類型不確定,而且和對(duì)應(yīng)的對(duì)象執(zhí)行的類型也不一定一致。

這時(shí)就將泛型定義在方法上。

4.5 泛型接口

如圖4.19所示代碼。

4.19 泛型代碼

有可能在實(shí)現(xiàn)類里面也不能確定具體要操作的數(shù)據(jù)類型,所以可以這樣做,在實(shí)現(xiàn)類里面指定具體的數(shù)據(jù)類型,如圖4.20所示。

4.20 泛型接口

4.6 泛型通配符(了解)

下面來學(xué)習(xí)一個(gè)泛型中比較特殊的東西。這塊內(nèi)容作為了解即可。

看這個(gè)例子:如圖4.21所示。

4.21 代碼

這樣的話show里面就只能使用操作String類型的集合

下面呢,我們又有了一個(gè)hashset類型的集合,這樣的話show方法就沒法進(jìn)行操作了,因?yàn)?/span>hashset集合中存儲(chǔ)的是數(shù)字類型,如圖4.22所示。

4.22 代碼

這個(gè)時(shí)候可以使用泛型中的通配符。

泛型通配符的格式為:?  問號(hào)代表任意類型。

所以代碼需要把泛型改為?的格式,如圖4.23所示。

4.23 泛型通配符

為什么在這不使用T 呢?

T:表示聲明為一個(gè)具體類型變量

?:表示不確定類型的時(shí)候使用

這兩個(gè)類型見到的時(shí)候能看明白就可以了,一般我們?cè)陂_發(fā)的時(shí)候不會(huì)自己定義。

4.7 泛型的限定(了解)

先定義這兩個(gè)類,代碼如圖4.24所示。

4.24 代碼

如果在主函數(shù)中定義一個(gè)集合,泛型指定為student,最后調(diào)用show的時(shí)候肯定是會(huì)報(bào)錯(cuò)的。

注意:定義集合要保證左右兩邊的泛型類型一直。

現(xiàn)在我還想要這兩個(gè)集合都能調(diào)用show方法,該怎么做呢?

可以使用我們前面講的泛型限定符,是可以的,但是使用泛型限定符的時(shí)候什么類都可以接收,但是最后代碼在獲取getName()的時(shí)候可能會(huì)有安全隱患,如果不是Person及其子類,都會(huì)報(bào)錯(cuò)的。

T表示只接收一種類型的,寫?表示接收任意類型,現(xiàn)在我只想接收person或者是person的子類對(duì)象

所以在這里我們想要限定,傳入的元素類型,要么是Person,要么是Person的子類型,這時(shí)就可以使用泛型的高級(jí)應(yīng)用,泛型的限定。

代碼如圖4.25所示。

注意:show方法可以這樣改,這樣就只接收personperson的子類,最后還可以使用執(zhí)行getName()方法

在這要注意,下面調(diào)用的方法只能是person類中的方法。

4.25 泛型的限定

泛型的限定:

? extends E: 接口E類型或者E類型的子類型。

? super E: 接口E類型或者E的父類型。

4.8 泛型的限定在集合中應(yīng)用(了解)

api文檔中的應(yīng)用場(chǎng)景,如圖4.26所示。

在定義集合的泛型的時(shí)候,也可以實(shí)現(xiàn)泛型的限定來對(duì)集合中的元素進(jìn)行限制。


4.26 文檔

5章:Map詳解

5.1 Map概述

下面我們學(xué)習(xí)一下集合的剩余部分,map

Mapcollection都屬于頂層接口

Map集合的特點(diǎn):

1. Map是一個(gè)雙列集合,Collection是單列集合

2. Map一次存一對(duì)元素,是鍵值對(duì)的形式,鍵和值有對(duì)應(yīng)關(guān)系,Collection是一次存一個(gè)元素。

3. Map集合必須要保證集合中鍵的唯一性!

可以這樣理解,Collection中存儲(chǔ)的是光棍,Map集合存儲(chǔ)的是夫妻。

看下api文檔中map的方法,如圖5.1所示。

5.1 map介紹

map集合中常見功能介紹

1. 添加

V put(K key, V value) :將KV作為元素存儲(chǔ)到map集合,當(dāng)存入了相同        key時(shí),新的value會(huì)覆蓋原來的value,并返回原來的value。

void putAll(Map<? extends K,? extends V> m) :把一個(gè)map集合添加到另一         個(gè)map集合中

2. 刪除

clear():清空集合內(nèi)的元素

v remove(k): 安裝鍵刪除,返回被刪除的鍵對(duì)應(yīng)的值

3. 判斷

boolean containsKey(Object key):判斷集合中是否包含指定的key

boolean containsValue(Object value):判斷集合中是否包含指定的value

boolean isEmpty():判斷集合是否為空

4. 獲取

int size():獲取map集合中元素的個(gè)數(shù)

V get(Object key):通過鍵獲取值,還可以作為判斷某一個(gè)鍵是否存在的依據(jù)

Collections values():獲取map集合中所有元素的值。

Set keySet():獲取map集合中所有的鍵。

Set entrySet():獲取的是鍵值的映射關(guān)系,將映射關(guān)系封裝成對(duì)象存儲(chǔ)到了Set集合中。

注意:Map集合沒有迭代器,迭代器是Collection集合具備的。

Map集合取出所有元素的原理:先將map集合轉(zhuǎn)成set集合,再進(jìn)行跌代。

5.2 Map子類特點(diǎn)及使用

Map集合常見子類:

|--Hashtable:底層是哈希表數(shù)據(jù)結(jié)構(gòu),是同步的 (線程安全),速度慢,不允 許存放null鍵,null值,已被HashMap替代。

|--Properties:用于配置文件的定義和操作,使用頻率非常高,同時(shí)鍵和   值都是字符串。是集合中可以和IO技術(shù)相結(jié)合的對(duì)象,到了IO部分再  學(xué)習(xí)它和IO相關(guān)的功能。

|--HashMap:底層也是哈希表數(shù)據(jù)結(jié)構(gòu),是不同步的 (線程不安全),速度快,     允許存放null鍵,null值。

|--LinkedHashMap:可以保證HashMap集合有序,存入的順序和取出的  順序一致。

|--TreeMap:對(duì)集合中元素的鍵進(jìn)行排序。

添加元素的時(shí)候注意了,如果指定的鍵已經(jīng)存在了,那么put語句會(huì)有返回值。返回原始值,并把新值覆蓋上去。

Map操作案例代碼如圖5.2所示。


5.2 map的操作

5.3 Map取出方式一keySet

下面看一下如何獲取map中所有的元素,單獨(dú)使用get是不行的。

如何獲取集合中所有的元素呢?

第一種方式:

先獲取所有的key(),再通過對(duì)所有的key進(jìn)行遍歷,在遍歷中通過get方法獲取每一個(gè)key對(duì)應(yīng)的value。

使用Map結(jié)合中的keySet方法,可以獲取Map集合中key的集合。

獲取所有的keyvalue,代碼如圖5.3所示。

5.3 獲取集合中的元素

畫圖分析這個(gè)過程,如圖5.4所示。

5.4 取值流程

5.4 Map取出方式二entrySet

第二種方式:

先獲取map中的鍵值關(guān)系封裝成一個(gè)個(gè)的entry對(duì)象,存儲(chǔ)到一個(gè)set集合中,再迭代這個(gè)set集合,根據(jù)entry獲取對(duì)應(yīng)的keyvalue。

代碼如圖5.5所示。

5.5 獲取map集合中的元素

畫圖分析這個(gè)流程,如圖5.6所示:

5.6 取值流程分析

5.5 HashMap集合中存儲(chǔ)自定義對(duì)象

需求:

每一個(gè)學(xué)生都有自己的歸屬地

學(xué)生有姓名和年齡屬性,將學(xué)生封裝成student對(duì)象。

因?yàn)閷W(xué)生對(duì)象和歸屬地有對(duì)應(yīng)關(guān)系,所以用map集合存儲(chǔ)該元素。

鍵:Student

值:String

注意:同姓名和同年齡的學(xué)生視為同一個(gè)人。

先建立一個(gè)student類,代碼如下5.7所示。

5.7 student

先演示正常數(shù)據(jù)插入,最后再插入一個(gè)相同元素,在這里我們認(rèn)為姓名和年齡相同就是同一元素。代碼如圖5.8所示。

5.8 代碼

要保證學(xué)生對(duì)象的唯一性,需要建立學(xué)生對(duì)象自身的判斷相同的依據(jù)。

因?yàn)槭谴娣诺搅?/span>Hash表中,所以需要覆蓋hashcodeequals方法。

代碼如圖5.9所示。

5.9 修改后的代碼

5.6保證HashMap集合有序-LinkedHashMap

現(xiàn)在數(shù)據(jù)可以存進(jìn)去了,但是現(xiàn)在是無序的。

之前在說set集合的時(shí)候下面有一個(gè)子類,linkedHashSet,可以保證順序

對(duì)應(yīng)map的話也有一個(gè)linkedHashMap,可以保證存入的順序和取出的順序一致,代碼如圖5.10所示。

5.10 linkedHashMap的使用

5.7 TreeMap

現(xiàn)在我想對(duì)集合中的元素按照指定的順序排序

這個(gè)時(shí)候就需要使用TreeMap了,代碼如圖5.11所示:

5.11 TreeMap的用法

5.8 獲取Map中的所有值-values方法

現(xiàn)在的需求,我就想拿到所有學(xué)生的歸屬地,想看看他們都來自于哪。

代碼如圖5.12所示。

5.12 values方法

5.9 Map集合擴(kuò)展

某機(jī)構(gòu)有線上班和線下班。

線上班:

01 zhangsan

02 lisi

線下班:

01 wangwu

02 zhaoliu

這個(gè)時(shí)候就可以在Map中存儲(chǔ)Map了。(當(dāng)然也可以在map中存儲(chǔ)自定義對(duì)象)

線上班有很多學(xué)生,線下班也有很多學(xué)生

需要有一個(gè)map存儲(chǔ)線上學(xué)生的編號(hào)和姓名

需要有一個(gè)map存儲(chǔ)線下學(xué)生的編號(hào)和姓名

因?yàn)榫€下和線上都屬于某機(jī)構(gòu),

所以某機(jī)構(gòu)也是一個(gè)集合

這個(gè)集合里面有兩種類型的班級(jí)。

所以就是類似這種格式的

某機(jī)構(gòu)<班級(jí)類型,學(xué)生集合<學(xué)生編號(hào),學(xué)生姓名>>

代碼實(shí)現(xiàn)如圖5.13所示。

5.13 嵌套map

5.10 MapUtils工具類

需求如下:

 單詞計(jì)數(shù)案例

      需求:統(tǒng)計(jì)字符串中相同單詞出現(xiàn)的次數(shù)

      輸出結(jié)果

             單詞:出現(xiàn)總次數(shù)

代碼如圖5.14所示。

5.14 單詞計(jì)數(shù)案例

針對(duì)上面的代碼可以使用MapUtils進(jìn)行改造,改造之后如圖5.15所示。

注意:在使用MapUtils的時(shí)候需要添加commons-collections依賴jar包。

commons-collections拷貝到項(xiàng)目的lib目錄下,然后buildPath即可使用。

5.15 MapUtils的使用

MapUtils.getInteger(map, key, defaultValue);

這行代碼的意思是從map這個(gè)集合中根據(jù)key查詢value值,如果查詢不到的話就返回defaultValue。能查詢到的話就返回key對(duì)應(yīng)的value值。

6章:集合工具類

如圖6.1所示的集合關(guān)系圖,大部分常用的都講了,現(xiàn)在就剩右下角的工具包沒有講了。

java集合類

6.1集合關(guān)系圖

假設(shè)要對(duì)ArrayList中的元素進(jìn)行排序,那么直接存儲(chǔ)到TreeSet中不就有序了嗎?

但是我們的元素是有重復(fù)的,不能直接存到TreeSet里面。

這時(shí)就可以考慮使用集合框架的工具類來完成。

集合中的工具類有兩個(gè)。

Collections

Arrays

這兩個(gè)工具類的特點(diǎn):類中的方法都是靜態(tài)的,不需要?jiǎng)?chuàng)建對(duì)象,直接使用類名調(diào)用即可。

下面先學(xué)習(xí)一下Collections工具類的一些用法

6.1 Collections-sort 方法

api文檔中的介紹,如圖6.2所示、

6.2 Collections工具類介紹

這個(gè)類里面都是靜態(tài)方法。

Collections:集合對(duì)象的工具類,提供了操作集合的方法

需求:

想對(duì)這個(gè)集合中的元素進(jìn)行排序,按照字典順序排序。代碼實(shí)現(xiàn)如圖6.3所示。

6.3 集合元素排序

6.2 Collections-reverseOrder方法

如果想要按照倒序排序呢?可以使用Collections中的倒序比較器。

代碼如圖6.4所示。

6.4 倒序排序

6.3 Collections-max方法

按照自然順序獲取最大值,如圖6.5所示。

6.5 獲取最大值

6.4 Collections-其他方法

代碼如圖6.6所示。

6.6 Collections中的其他方法

下面這個(gè)要注意一下

Collections:

List synchronizedList(List list):可以將一個(gè)不同步(線程不安全)list集合轉(zhuǎn)成一個(gè)同步(線程安全)list集合。

XXX synchronizedXXX(XXX xxx):將非同步的集合變成同步集合的方法。

多個(gè)線程操作ArrayList,會(huì)造成數(shù)據(jù)錯(cuò)亂。Vector是線程安全的,但是效率很低。

可以自己加鎖,但是這樣比較麻煩

所以集合工具類提供了一個(gè)比較方便的方法,將非同步的集合變成同步集合的方法。

6.5 Arrays

Arrays:提供了操作數(shù)組的方法。

這個(gè)類里面就幾個(gè)方法,其余的都是對(duì)應(yīng)的重載方法。

這里面有一個(gè)比較重要的方法

asList:數(shù)組變集合

代碼如圖6.7所示、

6.7 asList的使用

數(shù)組轉(zhuǎn)成集合之后有什么好處?

當(dāng)數(shù)組變成集合后,就可以使用集合的方法來操作數(shù)組,而不用自己再寫代碼操作數(shù)組了,但是有些方法是不可以使用的,只要是改變集合長(zhǎng)度的方法都不能用,因?yàn)閿?shù)組是固定長(zhǎng)度的。

Arraystostring方法

把數(shù)組轉(zhuǎn)為字符串,代碼如圖6.8所示。

6.8 數(shù)組轉(zhuǎn)字符串

6.6 集合轉(zhuǎn)成數(shù)組

說完了數(shù)組變集合,咱們?cè)倏纯醇献償?shù)組

apiCollection的方法,第一個(gè)返回值是object數(shù)組,需要強(qiáng)制轉(zhuǎn)換。

第二個(gè)是一個(gè)泛型,這個(gè)就不需要強(qiáng)轉(zhuǎn)了。如圖6.9所示

6.9 API文檔介紹

看這個(gè)例子,代碼如圖6.10所示。

6.10 集合轉(zhuǎn)數(shù)組

在這其實(shí)指定數(shù)組的長(zhǎng)度使用集合的size方法最合適,如圖6.11所示。

當(dāng)指定的長(zhǎng)度小于集合的長(zhǎng)度,該方法內(nèi)部會(huì)自動(dòng)創(chuàng)建一個(gè)該類型的新數(shù)組長(zhǎng)度和集合長(zhǎng)度一致,用于存儲(chǔ)集合中的元素。

如果指定的數(shù)組長(zhǎng)度等于集合的長(zhǎng)度,那么該方法就不會(huì)創(chuàng)建新數(shù)組,而是使用傳遞進(jìn)來的數(shù)組。

所以在定義數(shù)組時(shí),最好定義長(zhǎng)度和集合長(zhǎng)度相同的數(shù)組,這樣就不用創(chuàng)建新數(shù)組了。

6.11 集合轉(zhuǎn)數(shù)組

將集合轉(zhuǎn)成數(shù)組有什么用呢?

其實(shí)是限定了對(duì)元素的增刪操作。

7章:增強(qiáng)for循環(huán)

7.1增強(qiáng)for循環(huán)

最開始可以這樣迭代集合中的元素,如圖7.1所示。

7.1 迭代操作

但是天天這樣寫發(fā)現(xiàn)也比較麻煩。

發(fā)現(xiàn)collection有一個(gè)父類,iterable接口,實(shí)現(xiàn)這個(gè)接口的類是可以使用foreach循環(huán)操作的。文檔解釋 如圖7.2所示。

7.2 文件介紹

JDK1.5版本以后的新特性,Collection有一個(gè)父接口Iterable

該接口的出現(xiàn)封裝了iterator方法,并提供了一個(gè)增強(qiáng)for循環(huán)。

格式:

for(元素類型變量 : 數(shù)組或者Collection集合)

{

}

例子:這樣發(fā)現(xiàn)代碼就非常簡(jiǎn)潔了。如圖7.3所示。

7.3 foreach迭代

增強(qiáng)for循環(huán)和傳統(tǒng)for循環(huán)有什么不同呢?

增強(qiáng)for循環(huán)在使用時(shí),必須要有被遍歷的目標(biāo),而且只能遍歷數(shù)組和Collection集合,簡(jiǎn)化了迭代。

傳統(tǒng)for循環(huán),它的應(yīng)用更為普遍。

注意:如果在遍歷的時(shí)候需要用到角標(biāo),還是要用傳統(tǒng)的for循環(huán)。

8章:可變參數(shù)


8.1 函數(shù)中的可變參數(shù)

如果不確定參數(shù)數(shù)量的話,可以使用數(shù)組來傳遞參數(shù),代碼如圖8.1所示。

8.1 代碼

如果操作的參數(shù)變化的時(shí)候,需要重新定義一個(gè)數(shù)組,如圖8.2所示。

當(dāng)一個(gè)函數(shù)操作的參數(shù)類型一致,但是參數(shù)個(gè)數(shù)不一致的時(shí)候,可以定義成該類型的數(shù)組參數(shù),這樣使用者就可以吧元素封裝成一個(gè)數(shù)組,再進(jìn)行傳遞即可。

8.2 代碼

我們發(fā)現(xiàn),當(dāng)傳遞的參數(shù)發(fā)生了變化,就要new一個(gè)數(shù)組,是比較麻煩的,所以jdk1.5以后出現(xiàn)了新特性,可變參數(shù)。,如圖8.3所示。

可變參數(shù)的格式:數(shù)據(jù)類型...

例如:int...

在這給show2方法直接傳遞一個(gè)數(shù)組也是可以的。因?yàn)榭勺儏?shù)默認(rèn)會(huì)把接收到的參數(shù)封裝到一個(gè)數(shù)組中,如果本來指定的就是數(shù)組,那么就直接拿來用了。

8.3 可變參數(shù)

注意:如果函數(shù)上有多個(gè)參數(shù),可變參數(shù)一定要定義在參數(shù)列表最后面。

如圖8.4所示。

8.4 可變參數(shù)

注意:如果可變參數(shù)變量不放在最后面的話,這種情況可能就把show3中的所有參數(shù)都傳給arr這個(gè)可變參數(shù)了,最后面的a這個(gè)參數(shù)就沒值了。

public static void show3(int... arr , int a) {

              System.out.println("a="+a);

              for (int i : arr) {

                     System.out.println(i);

              }

       }

    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多

    免费大片黄在线观看国语| 91福利视频日本免费看看 | 日韩精品一区二区毛片 | 国产一区二区三区成人精品| 国产综合欧美日韩在线精品| 午夜精品国产一区在线观看| 中文字幕免费观看亚洲视频| 日本高清二区视频久二区| 高清亚洲精品中文字幕乱码| 日本午夜免费啪视频在线| 国产成人免费高潮激情电| 国产小青蛙全集免费看| 欧美日韩国产精品第五页| 不卡一区二区在线视频| 国产日韩欧美一区二区| 日韩一区二区三区高清在| 亚洲天堂有码中文字幕视频| 国产精品人妻熟女毛片av久久| 欧美日本道一区二区三区| 又黄又色又爽又免费的视频| 亚洲天堂国产精品久久精品| 国产丝袜女优一区二区三区| 日韩一级毛一欧美一级乱| 欧美一区二区三区十区| 亚洲黄香蕉视频免费看| 中文字幕日韩一区二区不卡| 国产精品视频一区麻豆专区| 欧美熟妇一区二区在线| 亚洲精品成人综合色在线| 亚洲午夜福利视频在线| 九九热视频免费在线视频| 国产又粗又猛又大爽又黄| 人妻久久一区二区三区精品99| 国产精品久久久久久久久久久痴汉| 亚洲欧美日韩在线看片| 色欧美一区二区三区在线| 欧美精品久久99九九| 国产小青蛙全集免费看| 丰满人妻少妇精品一区二区三区| 国产主播精品福利午夜二区| 最新日韩精品一推荐日韩精品|