1. 程式人生 > >集合框架與泛型

集合框架與泛型

元素存在 lse 鍵值對 tree 二分 support linked tor efi

集合框架:★★★★★,用於存儲數據的容器。

特點:

1:對象封裝數據,對象多了也需要存儲。集合用於存儲對象

2:對象的個數確定可以使用數組,但是不確定怎麽辦?可以用集合。因為集合是可變長度的。

集合和數組的區別:

1:數組是固定長度的;集合可變長度的。

2:數組可以存儲基本數據類型,也可以存儲引用數據類型;集合只能存儲引用數據類型

3:數組存儲的元素必須是同一個數據類型;集合存儲的對象可以是不同數據類型。

數據結構:就是容器中存儲數據的方式。

對於集合容器,有很多種。因為每一個容器的自身特點不同,其實原理在於每個容器的內部數據結構不同。

集合容器在不斷向上抽取過程中。出現了集合體系。

在使用一個體系時,原則:參閱頂層內容。建立底層對象。

------------------------------------------------------------

--< java.util >-- Collection接口:

Collection

|--List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重復。

|--Set:無序(存入和取出順序有可能不一致),不可以存儲重復元素。必須保證元素唯一性。

1,添加:

add(object):添加一個元素

addAll(Collection) :添加一個集合中的所有元素。

2,刪除:

clear():將集合中的元素全刪除,清空集合

remove(obj) :刪除集合中指定的對象。註意:刪除成功,集合的長度會改變。

removeAll(collection) :刪除部分元素。部分元素和傳入Collection一致。

3,判斷:

boolean contains(obj) :集合中是否包含指定元素 。

boolean containsAll(Collection) :集合中是否包含指定的多個元素。

boolean isEmpty():集合中是否有元素。

4,獲取:

int size():集合中有幾個元素。

5,取交集:

boolean retainAll(Collection) :對當前集合中保留和指定集合中的相同的元素。如果兩個集合元素相同,返回flase;如果retainAll修改了當前集合,返回true。

6,獲取集合中所有元素:

Iterator iterator()叠代器

7,將集合變成數組:

toArray();

------------------------------------------------------------

--< java.util >-- Iterator接口:

叠代器:是一個接口。作用:用於取集合中的元素。

boolean

hasNext() 如果仍有元素可以叠代,則返回 true。

E

next() 返回叠代的下一個元素。

void

remove() 從叠代器指向的 collection 中移除叠代器返回的最後一個元素(可選操作)。

每一個集合都有自己的數據結構(就是容器中存儲數據的方式),都有特定的取出自己內部元素的方式。為了便於操作所有的容器,取出元素。將容器內部的取出方式按照一個統一的規則向外提供,這個規則就是Iterator接口

也就說,只要通過該接口就可以取出Collection集合中的元素,至於每一個具體的容器依據自己的數據結構,如何實現的具體取出細節,這個不用關心,這樣就降低了取出元素和具體集合的耦合性。

Iterator it = coll.iterator();//獲取容器中的叠代器對象,至於這個對象是是什麽不重要。這對象肯定符合一個規則Iterator接口。

-----------------------------------------------------------------------------

public static void main(String[] args) {

Collection coll = new ArrayList();

coll.add("abc0");

coll.add("abc1");

coll.add("abc2");

//--------------方式1----------------------

Iterator it = coll.iterator();

while(it.hasNext()){

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

}

//---------------方式2用此種----------------------

for(Iterator it = coll.iterator();it.hasNext(); ){

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

}

}

-----------------------------------------------------------------------------

--< java.util >-- List接口:

List本身是Collection接口的子接口,具備了Collection的所有方法。現在學習List體系特有的共性方法,查閱方法發現List的特有方法都有索引,這是該集合最大的特點。

List:有序(元素存入集合的順序和取出的順序一致),元素都有索引。元素可以重復。

|--ArrayList:底層的數據結構是數組,線程不同步,ArrayList替代了Vector,查詢元素的速度非常快。

|--LinkedList:底層的數據結構是鏈表,線程不同步,增刪元素的速度非常快。

|--Vector:底層的數據結構就是數組,線程同步的Vector無論查詢和增刪都巨慢。

1,添加:

add(index,element) :在指定的索引位插入元素。

addAll(index,collection) :在指定的索引位插入一堆元素。

2,刪除:

remove(index) :刪除指定索引位的元素。 返回被刪的元素。

3,獲取:

Object get(index) :通過索引獲取指定元素。

int indexOf(obj) :獲取指定元素第一次出現的索引位,如果該元素不存在返回-1;

所以,通過-1,可以判斷一個元素是否存在。

int lastIndexOf(Object o) :反向索引指定元素的位置。

List subList(start,end) :獲取子列表。

4,修改:

Object set(index,element) :對指定索引位進行元素的修改。

5,獲取所有元素

ListIterator listIterator()list集合特有的叠代器。

List集合支持對元素的增、刪、改、查。

List集合因為角標有了自己的獲取元素的方式: 遍歷。

for(int x=0; x<list.size(); x++){

sop("get:"+list.get(x));

}

在進行list列表元素叠代的時候,如果想要在叠代過程中,想要對元素進行操作的時候,比如滿足條件添加新元素。會發生.ConcurrentModificationException並發修改異常。

導致的原因是:

集合引用和叠代器引用在同時操作元素,通過集合獲取到對應的叠代器後,在叠代中,進行集合引用的元素添加,叠代器並不知道,所以會出現異常情況。

如何解決呢?

既然是在叠代中對元素進行操作,找叠代器的方法最為合適.可是Iterator中只有hasNext,next,remove方法.通過查閱的它的子接口,ListIterator,發現該列表叠代器接口具備了對元素的增、刪、改、查的動作。

ListIterator是List集合特有的叠代器

ListIterator it = list.listIterator;//取代Iterator it = list.iterator;

方法摘要

void

add(E e) 將指定的元素插入列表(可選操作)。

boolean

hasNext() 以正向遍歷列表時,如果列表叠代器有多個元素,則返回 true(換句話說,如果 next 返回一個元素而不是拋出異常,則返回 true)。

boolean

hasPrevious() 如果以逆向遍歷列表,列表叠代器有多個元素,則返回 true。

E

next() 返回列表中的下一個元素。

int

nextIndex() 返回對 next 的後續調用所返回元素的索引。

E

previous() 返回列表中的前一個元素。

int

previousIndex() 返回對 previous 的後續調用所返回元素的索引。

void

remove() 從列表中移除由 next 或 previous 返回的最後一個元素(可選操作)。

void

set(E e) 用指定元素替換 next 或 previous 返回的最後一個元素(可選操作)。

可變長度數組的原理:

當元素超出數組長度,會產生一個新數組,將原數組的數據復制到新數組中,再將新的元素添加到新數組中。

ArrayList:是按照原數組的50%延長。構造一個初始容量為 10 的空列表。

Vector:是按照原數組的100%延長。

註意:對於list集合,底層判斷元素是否相同,其實用的是元素自身的equals方法完成的。所以建議元素都要復寫equals方法,建立元素對象自己的比較相同的條件依據。

LinkedList:的特有方法。

addFirst();

addLast();

jdk1.6以後。

offerFirst();

offerLast();

getFirst():獲取鏈表中的第一個元素。如果鏈表為空,拋出NoSuchElementException;

getLast();獲取鏈表中的最後一個元素。如果鏈表為空,拋出NoSuchElementException;

jdk1.6以後。

peekFirst();獲取鏈表中的第一個元素。如果鏈表為空,返回null。

peekLast();

removeFirst():獲取鏈表中的第一個元素,但是會刪除鏈表中的第一個元素。如果鏈表為空,拋出NoSuchElementException

removeLast();

jdk1.6以後。

pollFirst();獲取鏈表中的第一個元素,但是會刪除鏈表中的第一個元素。如果鏈表為空,返回null。

pollLast();

------------------------------------------------------------

<閱讀到此>--< java.util >-- Set接口

數據結構:數據的存儲方式;

Set接口中的方法和Collection中方法一致的。Set接口取出方式只有一種,叠代器

|--HashSet:底層數據結構是哈希表,線程是不同步的無序,高效;

HashSet集合保證元素唯一性:通過元素的hashCode方法,和equals方法完成的。

當元素的hashCode值相同時,才繼續判斷元素的equals是否為true。

如果為true,那麽視為相同元素,不存。如果為false,那麽存儲。

如果hashCode值不同,那麽不判斷equals,從而提高對象比較的速度。

|--LinkedHashSet:有序,hashset的子類。

|--TreeSet:Set集合中的元素的進行指定順序的排序。不同步TreeSet底層的數據結構就是二叉樹。

哈希表的原理:

1,對對象元素中的關鍵字(對象中的特有數據),進行哈希算法的運算,並得出一個具體的算法值,這個值 稱為哈希值

2,哈希值就是這個元素的位置。

3,如果哈希值出現沖突,再次判斷這個關鍵字對應的對象是否相同。如果對象相同,就不存儲,因為元素重復。如果對象不同,就存儲,在原來對象的哈希值基礎 +1順延。

4,存儲哈希值的結構,我們稱為哈希表。

5,既然哈希表是根據哈希值存儲的,為了提高效率,最好保證對象的關鍵字是唯一的。

這樣可以盡量少的判斷關鍵字對應的對象是否相同,提高了哈希表的操作效率。

對於ArrayList集合,判斷元素是否存在,或者刪元素底層依據都是equals方法。

對於HashSet集合,判斷元素是否存在,或者刪除元素,底層依據的是hashCode方法和equals方法。

TreeSet:

用於對Set集合進行元素的指定順序排序,排序需要依據元素自身具備的比較性。

如果元素不具備比較性,在運行時會發生ClassCastException異常。

所以需要元素實現Comparable接口,強制讓元素具備比較性,復寫compareTo方法

依據compareTo方法的返回值,確定元素在TreeSet數據結構中的位置。

TreeSet方法保證元素唯一性的方式:就是參考比較方法的結果是否為0,如果return 0,視為兩個對象重復,不存。

註意:在進行比較時,如果判斷元素不唯一,比如,同姓名,同年齡,才視為同一個人。

在判斷時,需要分主要條件和次要條件,當主要條件相同時,再判斷次要條件,按照次要條件排序。

TreeSet集合排序有兩種方式,Comparable和Comparator區別:

1:讓元素自身具備比較性,需要元素對象實現Comparable接口,覆蓋compareTo方法。

2:讓集合自身具備比較性,需要定義一個實現了Comparator接口的比較器,並覆蓋compare方法,並將該類對象作為實際參數傳遞給TreeSet集合的構造函數。

第二種方式較為靈活。

------------------------------------------------------------

Map集合:

|--Hashtable:底層是哈希表數據結構,是線程同步的。不可以存儲null鍵,null值。

|--HashMap:底層是哈希表數據結構,是線程不同步的。可以存儲null鍵,null值。替代了Hashtable.

|--TreeMap:底層是二叉樹結構,可以對map集合中的鍵進行指定順序的排序。

Map集合存儲和Collection有著很大不同:

Collection一次存一個元素;Map一次存一對元素。

Collection是單列集合;Map是雙列集合。

Map中的存儲的一對元素:一個是鍵,一個是值,鍵與值之間有對應(映射)關系。

特點:要保證map集合中鍵的唯一性。

1,添加。

put(key,value):當存儲的鍵相同時,新的值會替換老的值,並將老值返回。如果鍵沒有重復,返回null。

void putAll(Map);

2,刪除。

void clear():清空

value remove(key) :刪除指定鍵。

3,判斷。

boolean isEmpty():

boolean containsKey(key):是否包含key

boolean containsValue(value) :是否包含value

4,取出。

int size():返回長度

value get(key) :通過指定鍵獲取對應的值。如果返回null,可以判斷該鍵不存在。當然有特殊情況,就是在hashmap集合中,是可以存儲null鍵null值的。

Collection values():獲取map集合中的所有的值。

5,想要獲取map中的所有元素

原理:map中是沒有叠代器的,collection具備叠代器,只要將map集合轉成Set集合,可以使用叠代器了。之所以轉成set,是因為map集合具備著鍵的唯一性,其實set集合就來自於map,set集合底層其實用的就是map的方法。

map集合轉成set的方法:

Set keySet();

Set entrySet();//取的是鍵和值的映射關系。

Entry就是Map接口中的內部接口;

為什麽要定義在map內部呢?entry是訪問鍵值關系的入口,是map的入口,訪問的是map中的鍵值對。

---------------------------------------------------------

取出map集合中所有元素的方式一:keySet()方法。

可以將map集合中的鍵都取出存放到set集合中。對set集合進行叠代。叠代完成,再通過get方法對獲取到的鍵進行值的獲取。

Set keySet = map.keySet();

Iterator it = keySet.iterator();

while(it.hasNext()) {

Object key = it.next();

Object value = map.get(key);

System.out.println(key+":"+value);

}

--------------------------------------------------------

取出map集合中所有元素的方式二:entrySet()方法。

Set entrySet = map.entrySet();

Iterator it = entrySet.iterator();

while(it.hasNext()) {

Map.Entry me = (Map.Entry)it.next();

System.out.println(me.getKey()+"::::"+me.getValue());

}

--------------------------------------------------------

使用集合的技巧:

看到Array就是數組結構,有角標,查詢速度很快。

看到link就是鏈表結構:增刪速度快,而且有特有方法。addFirst; addLast; removeFirst(); removeLast(); getFirst();getLast();

看到hash就是哈希表,就要想要哈希值,就要想到唯一性,就要想到存入到該結構的中的元素必須覆蓋hashCode,equals方法。

看到tree就是二叉樹,就要想到排序,就想要用到比較。

比較的兩種方式:

一個是Comparable:覆蓋compareTo方法;

一個是Comparator:覆蓋compare方法。

LinkedHashSet,LinkedHashMap:這兩個集合可以保證哈希表有存入順序和取出順序一致,保證哈希表有序。

集合什麽時候用?

當存儲的是一個元素時,就用Collection。當存儲對象之間存在著映射關系時,就使用Map集合。

保證唯一,就用Set。不保證唯一,就用List。

------------------------------------------------------------------------------------------------

Collections:它的出現給集合操作提供了更多的功能。這個類不需要創建對象,內部提供的都是靜態方法。

靜態方法:

Collections.sort(list);//list集合進行元素的自然順序排序。

Collections.sort(list,new ComparatorByLen());//按指定的比較器方法排序。

class ComparatorByLen implements Comparator<String>{

public int compare(String s1,String s2){

int temp = s1.length()-s2.length();

return temp==0?s1.compareTo(s2):temp;

}

}

Collections.max(list); //返回list中字典順序最大的元素。

int index = Collections.binarySearch(list,"zz");//二分查找,返回角標。

Collections.reverseOrder();//逆向反轉排序。

Collections.shuffle(list);//隨機對list中的元素進行位置的置換。

將非同步集合轉成同步集合的方法:Collections中的 XXX synchronizedXXX(XXX);

List synchronizedList(list);

Map synchronizedMap(map);

原理:定義一個類,將集合所有的方法加同一把鎖後返回。

Collection 和 Collections的區別

Collections是個java.util下的類,是針對集合類的一個工具,提供一系列靜態方法,實現對集合的查找、排序、替換、線程安全化(將非同步的集合轉換成同步的)等操作。

Collection是個java.util下的接口,它是各種集合結構的父接口,繼承於它的接口主要有Set和List,提供了關於集合的一些操作,如插入、刪除、判斷一個元素是否其成員、遍歷等。

-------------------------------------------------------

Arrays:

用於操作數組對象的工具類,裏面都是靜態方法。

asList方法將數組轉換成list集合。

String[] arr = {"abc","kk","qq"};

List<String> list = Arrays.asList(arr);//將arr數組轉成list集合。

將數組轉換成集合,有什麽好處呢?用aslist方法,將數組變成集合;

可以通過list集合中的方法來操作數組中的元素:isEmpty()、contains、indexOf、set;

註意(局限性):數組是固定長度,不可以使用集合對象增加或者刪除等,會改變數組長度的功能方法。比如add、remove、clear。(會報不支持操作異常UnsupportedOperationException);

如果數組中存儲的引用數據類型,直接作為集合的元素可以直接用集合方法操作。

如果數組中存儲的是基本數據類型,asList會將數組實體作為集合元素存在。

集合變數組:用的是Collection接口中的方法:toArray();

如果給toArray傳遞的指定類型的數據長度小於了集合的size,那麽toArray方法,會自定再創建一個該類型的數據,長度為集合的size。

如果傳遞的指定的類型的數組的長度大於了集合的size,那麽toArray方法,就不會創建新數組,直接使用該數組即可,並將集合中的元素存儲到數組中,其他為存儲元素的位置默認值null。

所以,在傳遞指定類型數組時,最好的方式就是指定的長度和size相等的數組。

將集合變成數組後有什麽好處?限定了對集合中的元素進行增刪操作,只要獲取這些元素即可。

------------------------------------------------------------------------------------------------

Jdk5.0新特性:

Collection在jdk1.5以後,有了一個父接口Iterable,這個接口的出現的將iterator方法進行抽取,提高了擴展性。

--------------------------------------------------

增強for循環:foreach語句,foreach簡化了叠代器。

格式:// 增強for循環括號裏寫兩個參數,第一個是聲明一個變量,第二個就是需要叠代的容器

for( 元素類型 變量名 : Collection集合 & 數組 ) {

}

高級for循環和傳統for循環的區別:

高級for循環在使用時,必須要明確被遍歷的目標。這個目標,可以是Collection集合或者數組,如果遍歷Collection集合,在遍歷過程中還需要對元素進行操作,比如刪除,需要使用叠代器。

如果遍歷數組,還需要對數組元素進行操作,建議用傳統for循環因為可以定義角標通過角標操作元素。如果只為遍歷獲取,可以簡化成高級for循環,它的出現為了簡化書寫。

高級for循環可以遍歷map集合嗎?不可以。但是可以將map轉成set後再使用foreach語句。

1)、作用:對存儲對象的容器進行叠代: 數組 collection map

2)、增強for循環叠代數組:

String [] arr = {"a", "b", "c"};//數組的靜態定義方式,只試用於數組首次定義的時候

for(String s : arr) {

System.out.println(s);

}

3)、單列集合 Collection:

List list = new ArrayList();

list.add("aaa");

// 增強for循環, 沒有使用泛型的集合能不能使用增強for循環叠代?能

for(Object obj : list) {

String s = (String) obj;

System.out.println(s);

}

4)、雙列集合 Map:

Map map = new HashMap();

map.put("a", "aaa");

// 傳統方式:必須掌握這種方式

Set entrys = map.entrySet(); // 1.獲得所有的鍵值對Entry對象

iter = entrys.iterator(); // 2.叠代出所有的entry

while(iter.hasNext()) {

Map.Entry entry = (Entry) iter.next();

String key = (String) entry.getKey(); // 分別獲得key和value

String value = (String) entry.getValue();

System.out.println(key + "=" + value);

}

// 增強for循環叠代:原則上map集合是無法使用增強for循環來叠代的,因為增強for循環只能針對實現了Iterable接口的集合進行叠代;Iterable是jdk5中新定義的接口,就一個方法iterator方法,只有實現了Iterable接口的類,才能保證一定有iterator方法,java有這樣的限定是因為增強for循環內部還是用叠代器實現的,而實際上,我們可以通過某種方式來使用增強for循環。

for(Object obj : map.entrySet()) {

Map.Entry entry = (Entry) obj; // obj 依次表示Entry

System.out.println(entry.getKey() + "=" + entry.getValue());

}

5)、集合叠代註意問題:在叠代集合的過程中,不能對集合進行增刪操作(會報並發訪問異常);可以用叠代器的方法進行操作(子類listIterator:有增刪的方法)。

6)、增強for循環註意問題:在使用增強for循環時,不能對元素進行賦值;

int[] arr = {1,2,3};

for(int num : arr) {

num = 0; //不能改變數組的值

}

System.out.println(arr[1]); //2

--------------------------------------------------

可變參數(...):用到函數的參數上,當要操作的同一個類型元素個數不確定的時候,可是用這個方式,這個參數可以接受任意個數的同一類型的數據。

和以前接收數組不一樣的是:

以前定義數組類型,需要先創建一個數組對象,再將這個數組對象作為參數傳遞給函數。現在,直接將數組中的元素作為參數傳遞即可。底層其實是將這些元素進行數組的封裝,而這個封裝動作,是在底層完成的,被隱藏了。所以簡化了用戶的書寫,少了調用者定義數組的動作。

如果在參數列表中使用了可變參數,可變參數必須定義在參數列表結尾(也就是必須是最後一個參數,否則編譯會失敗。)。

如果要獲取多個int數的和呢?可以使用將多個int數封裝到數組中,直接對數組求和即可。

---------------------------------------------------

靜態導入:導入了類中的所有靜態成員,簡化靜態成員的書寫。

import static java.util.Collections.*; //導入了Collections類中的所有靜態成員

---------------------------------------------------

枚舉:關鍵字 enum

問題:對象的某個屬性的值不能是任意的,必須為固定的一組取值其中的某一個;

解決辦法:

1)、在setGrade方法中做判斷,不符合格式要求就拋出異常;

2)、直接限定用戶的選擇,通過自定義類模擬枚舉的方式來限定用戶的輸入,寫一個Grade類,私有構造函數,對外提供5個靜態的常量表示類的實例;

3)jdk5中新定義了枚舉類型,專門用於解決此類問題;

4)、枚舉就是一個特殊的java類,可以定義屬性、方法、構造函數、實現接口、繼承類;

------------------------------------------------------------------------------

自動拆裝箱:java中數據類型分為兩種 : 基本數據類型 引用數據類型(對象)

java程序中所有的數據都需要當做對象來處理,針對8種基本數據類型提供了包裝類,如下:

int --> Integer

byte --> Byte

short --> Short

long --> Long

char --> Character

double --> Double

float --> Float

boolean --> Boolean

jdk5以前基本數據類型和包裝類之間需要互轉:

基本---引用 Integer x = new Integer(x);

引用---基本 int num = x.intValue();

1)Integer x = 1; x = x + 1; 經歷了什麽過程?裝箱 à 拆箱 à 裝箱

2)、為了優化,虛擬機為包裝類提供了緩沖池,Integer池的大小 -128~127 一個字節的大小

3)String池:Java為了優化字符串操作 提供了一個緩沖池;

----------------------------------------------------------

泛型:jdk1.5版本以後出現的一個安全機制。表現格式:< >

好處:

1:將運行時期的問題ClassCastException問題轉換成了編譯失敗,體現在編譯時期,程序員就可以解決問題。

2:避免了強制轉換的麻煩。

只要帶有<>的類或者接口,都屬於帶有類型參數的類或者接口,在使用這些類或者接口時,必須給<>中傳遞一個具體的引用數據類型。

泛型技術:其實應用在編譯時期,是給編譯器使用的技術,到了運行時期,泛型就不存在了。

為什麽? 因為泛型的擦除:也就是說,編輯器檢查了泛型的類型正確後,在生成的類文件中是沒有泛型的。

在運行時,如何知道獲取的元素類型而不用強轉呢?

泛型的補償:因為存儲的時候,類型已經確定了是同一個類型的元素,所以在運行時,只要獲取到該元素的類型,在內部進行一次轉換即可,所以使用者不用再做轉換動作了。

什麽時候用泛型類呢?

當類中的操作的引用數據類型不確定的時候,以前用的Object來進行擴展的,現在可以用泛型來表示。這樣可以避免強轉的麻煩,而且將運行問題轉移到的編譯時期。

----------------------------------------------------------

泛型在程序定義上的體現:

//泛型類:將泛型定義在類上。

class Tool<Q> {

private Q obj;

public void setObject(Q obj) {

this.obj = obj;

}

public Q getObject() {

return obj;

}

}

//當方法操作的引用數據類型不確定的時候,可以將泛型定義在方法上。

public <W> void method(W w) {

System.out.println("method:"+w);

}

//靜態方法上的泛型:靜態方法無法訪問類上定義的泛型。如果靜態方法操作的引用數據類型不確定的時候,必須要將泛型定義在方法上。

public static <Q> void function(Q t) {

System.out.println("function:"+t);

}

//泛型接口.

interface Inter<T> {

void show(T t);

}

class InterImpl<R> implements Inter<R> {

public void show(R r) {

System.out.println("show:"+r);

}

}

------------------------------------------------------------

泛型中的通配符:可以解決當具體類型不確定的時候,這個通配符就是 ? ;當操作類型時,不需要使用類型的具體功能時,只使用Object類中的功能。那麽可以用 ? 通配符來表未知類型。

泛型限定:

上限:?extends E:表示這個對象的實例,可以接收E類型或者E的子類型對象。

下限:?super E:可以接收E類型或者E的父類型對象。

上限什麽時候用:往集合中添加元素時,既可以添加E類型對象,又可以添加E的子類型對象。為什麽?因為取的時候,E類型既可以接收E類對象,又可以接收E的子類型對象。

下限什麽時候用:當從集合中獲取元素進行操作的時候,可以用當前元素的類型接收,也可以用當前元素的父類型接收。

泛型的細節:

1泛型到底代表什麽類型取決於調用者傳入的類型,如果沒傳,默認是Object類型

2使用帶泛型的類創建對象時,等式兩邊指定的泛型必須一致

原因:編譯器檢查對象調用方法時只看變量,然而程序運行期間調用方法時就要考慮對象具體類型了

3等式兩邊可以在任意一邊使用泛型在另一邊不使用(考慮向後兼容)

ArrayList<String> al = new ArrayList<Object>(); //錯

//要保證左右兩邊的泛型具體類型一致就可以了,這樣不容易出錯。

ArrayList<? extends Object> al = new ArrayList<String>();

al.add("aa"); //錯,不能加String類型的對象

//因為集合具體對象中既可存儲String,也可以存儲Object的其他子類,所以添加具體的類型對象不合適,類型檢查會出現安全問題。 ?extends Object 代表Object的子類型不確定,怎麽能添加具體類型的對象呢?

public static void method(ArrayList<? extends Object> al) {

al.add("abc"); //錯

//只能對al集合中的元素調用Object類中的方法,具體子類型的方法都不能用,因為子類型不確定。

}

集合框架與泛型