Java学习笔记3——集合框架
文章目錄
- 1 集合的概念
- 2 Collection體系集合
- Collection父接口
- 3 List接口與實(shí)現(xiàn)類
- List接口
- List實(shí)現(xiàn)類
- ArrayList
- Vector
- LinkedList
- 4 Set接口與實(shí)現(xiàn)類
- Set接口
- Set實(shí)現(xiàn)類
- HashSet
- TreeSet
- 5 Map接口與實(shí)現(xiàn)類
- Map接口
- Map接口的內(nèi)部接口Entry
1 集合的概念
- 概念:對象的容器,實(shí)現(xiàn)了對對象常用的操作
- 與數(shù)組的區(qū)別:
1.數(shù)組長度固定,集合長度不固定;
2.數(shù)組可以存儲(chǔ)基本類型和引用類型,集合只能存儲(chǔ)引用類型 - 位置:集合類存放在java.util包中
2 Collection體系集合
Collection父接口
- 創(chuàng)建Collection集合ArrayList對象:Collection collection = new ArrayList();
常用方法
-
添加元素:
collection.add(E e); -
刪除元素:
移除指定:collection.remove(Object o);
移除所有:collection.clear(); -
遍歷元素(重點(diǎn)):
方法1:使用增強(qiáng)for(因?yàn)闊o下標(biāo))
for(Object obj : collection){ }方法2:使用迭代器
//創(chuàng)建集合 Collection collection = new ArrayList(); collection.add("xx");//略 //iterator接口有以下三個(gè)方法: //haNext(); 有沒有下一個(gè)元素 //next(); 獲取下一個(gè)元素 //remove(); 刪除當(dāng)前元素 Iterator it = collection.iterator(); while(it.hasNext()){String object = (String)it.next(); //注意別忘了Object到String要強(qiáng)轉(zhuǎn)// 可以使用it.remove(); 進(jìn)行移除元素}注意不能用collection的remove方法移除,collection的其他方法也不能用,因?yàn)榈髡谑褂弥现械脑?#xff0c;collection不能搶。否則會(huì)發(fā)生并發(fā)修改異常
- 判斷:
collection.contains(Object o); 檢查此集合是否包含對象o
collection.isEmpty();判斷此集合是否為空
3 List接口與實(shí)現(xiàn)類
List接口
- 特點(diǎn):有序、有下標(biāo)、元素可重復(fù)
- 創(chuàng)建List集合ArrayList對象:List list = new ArrayList<>();
舉例說明
-
添加元素:
list.add(); 會(huì)對基本類型進(jìn)行自動(dòng)裝箱 -
刪除元素:
可以用索引 list.remove(0)
當(dāng)刪除數(shù)字與索引矛盾時(shí) 對數(shù)字強(qiáng)轉(zhuǎn)
list.remove((Object) 10) 或 list.remove(new Integer(10)) -
遍歷:
使用for遍歷
for(int i = 0; i < lise.size(); i++){sout(list.get(i)); }使用增強(qiáng)for
for(Object list: collection){ }使用迭代器
Iterator it = collection.iterator(); while(it.hasNext()){String object = (String)it.next(); //強(qiáng)轉(zhuǎn)// 可以使用it.remove(); 進(jìn)行移除元素// 不能用collection.remove(); 不能用collection其他方法 會(huì)發(fā)生并發(fā)修改異常 }使用列表迭代器(注意和迭代器區(qū)別)
ListIterator li = list.listIterator(); while(li.hasNext()){System.out.println(li.nextIndex() + ":" + li.next()); //從前往后遍歷 }while(li.hasPrevious()){System.out.println(li.previousIndex() + ":" + li.previous()); //從后往前遍歷 }-
獲取
list.indexOf( ); -
返回子集合
sublist(x, y); 左閉右開
List subList = list.subList(1, 3); 返回索引 1、2
List實(shí)現(xiàn)類
ArrayList 【重點(diǎn)】
- 數(shù)組結(jié)構(gòu)實(shí)現(xiàn),必須要開辟連續(xù)空間,查詢快、增刪慢
- jdk1.2版本,運(yùn)行效率塊、線程不安全
Vector
- 數(shù)組結(jié)構(gòu)實(shí)現(xiàn),查詢快、增刪慢
- jdk1.0版本,運(yùn)行
LinkedList
- 雙向鏈表結(jié)構(gòu)實(shí)現(xiàn),無需開辟連續(xù)空間,增刪快,查詢慢
ArrayList
- 創(chuàng)建ArrayList集合對象:ArrayList arrayList = new ArrayList<>();
- 添加元素:
arrayList.add(); - 刪除元素:
【重點(diǎn)】在實(shí)際的業(yè)務(wù)需求中,或者邏輯上可以認(rèn)為姓名和年齡等信息可以唯一確定某個(gè)人,所以可以嘗試用以下代碼對元素進(jìn)行操作:
arrayList.remove(new Student("name", 10));但是直接使用的話并不會(huì)將其刪除,是因?yàn)檫@種方法是匹配內(nèi)容,需要重寫equals方法,因?yàn)锳rrayList的remove、contains、indexOf等方法的源碼中都調(diào)用了equals方法。
在Student類中重寫equals(this == obj) 方法:
public boolean equals(Object obj){//1 判斷是不是同一個(gè)對象if(this== obj){return true;}//2 判斷是否為空if(obj== null){return false;}//3 判斷是否是Student類型if(obj instanceof Student){Student== (Student)obj;//4 比較屬性if(this.name.equals(s.getName()) && this.age == s.getAge()){return true;}}//5 不滿足條件返回falsereturn false; }- 【重點(diǎn)】遍歷元素:
1.使用迭代器
Iterator it = arrayList.iterator(); while(it.hasNext()){Student s = (Student)it.next(); //強(qiáng)轉(zhuǎn) }2.使用列表迭代器
ListIterator li = arrayList.listIterator(); while(li.hasNext()){Student s = (Student)li.next(); //從前往后遍歷 }while(li.hasPrevious()){Student s = (Student)li.previous();//從后往前遍歷 }- 判斷
arrayList.contains(); 和 arrayList.isEmpty(); - 查找
arrayList.indexof();
源碼分析
ArrayList源碼中的常用常量:
注意:如果沒有向集合中添加任何元素時(shí)容量為0,添加一個(gè)后,容量為10,每次擴(kuò)容是原來的1.5倍
Vector
(開發(fā)中Vector不常用,了解一下即可)
- 創(chuàng)建Vector集合對象:Vector vector = new Vector<>();
- 增加、刪除、判斷同ArrayList
- 遍歷:(用枚舉器遍歷)
LinkedList
- 創(chuàng)建LinkedList集合對象:LinkedList li = new LinkedList<>();
- 常用方法與List一致
4 Set接口與實(shí)現(xiàn)類
Set接口
- 特點(diǎn):無序、無下標(biāo)、元素不可重復(fù)(一個(gè)不包含重復(fù)元素的Collection)
- 方法:全部繼承自Collection中的方法
增、刪、遍歷、判斷與Collection一致
Set實(shí)現(xiàn)類
HashSet【重點(diǎn)】
- 基于HashCode實(shí)現(xiàn)元素不重復(fù)
- 當(dāng)存入元素時(shí),會(huì)調(diào)用equals確認(rèn)其哈希碼是否跟已有元素相同,如果為true,則拒絕存入
TreeSet
- 基于排列順序?qū)崿F(xiàn)元素不重復(fù)
- 實(shí)現(xiàn)SortedSet接口,對集合元素自動(dòng)排序
- 元素對象的類型必須實(shí)現(xiàn)Comparable接口,指定排序規(guī)則
- 通過CompareTo方法確定是否為重復(fù)元素
HashSet
-
(其本質(zhì)就是HashMap,只使用HashMap的Key,add方法其實(shí)就是調(diào)用了HashMap的put方法)
-
存儲(chǔ)結(jié)構(gòu):哈希表(數(shù)組+鏈表+紅黑樹)
-
存儲(chǔ)過程(重復(fù)依據(jù)):
第一步:根據(jù)hashCode計(jì)算保存的位置,如果位置為空,直接保存,若不為空,進(jìn)行第二步
第二步:再執(zhí)行equals方法,如果equals為true(通常要重寫equals方法),則認(rèn)為是重復(fù),否則形成鏈表 -
特點(diǎn):基于HashCode計(jì)算元素存放位置
HashCode位置計(jì)算大致原理:
利用31這個(gè)質(zhì)數(shù),減少散列沖突
31提高執(zhí)行效率 31 * i = (i << 5) - i 轉(zhuǎn)為移位操作
當(dāng)存入元素的哈希碼相同時(shí),會(huì)調(diào)用equals進(jìn)行確認(rèn),如果結(jié)果為true,則拒絕后者存入。
可以看看java/util/Arrays.java里面的hashCode源碼:
上面的element.hashCode()中的hashCode()方法是java/lang/Object.java里的本地方法,本地方法封存在JDK中,要下載JDK開源代碼才能查看。源碼的邏輯如下:
字符串對象的哈希碼根據(jù)以下公式計(jì)算:
s[0]*31^(n-1) + s[1]*31^(n-2) + … + s[n-1]
使用 int 算法,這里 s[i] 是字符串的第 i 個(gè)字符的 ASCII 碼,n 是字符串的長度,^ 表示求冪。空字符串的哈希值為 0。
對元素的操作(大同小異):
- 新建集合:HashSet<T> hashSet = new HashSet<String>();
- 添加元素:hashSet.add( );
- 刪除元素:hashSet.remove( );
- 遍歷操作:
? 1. 增強(qiáng)for for( type type : hashSet)
? 2. 迭代器 Iterator<String> it = hashSet.iterator( ); - 判斷:hashSet.contains( ); hashSet.isEmpty();
需要注意:重寫了hashCode和equals方法之后,remove(new Person("劉德華",20));和contains(new Person("劉德華",20));等方法是可以成功刪除或者輸出的
TreeSet
(其本質(zhì)就是TreeMap,只使用TreeMap的Key,add方法其實(shí)就是調(diào)用了TreeMap的put方法)
- 特點(diǎn)
基于排列順序?qū)崿F(xiàn)元素不重復(fù)
實(shí)現(xiàn)SortedSet接口,對集合元素自動(dòng)排序
元素對象的類型必須實(shí)現(xiàn)Comparable接口,指定排序規(guī)則
通過CompareTo方法確定是否為重復(fù)元素 - 存儲(chǔ)結(jié)構(gòu):紅黑樹
- 創(chuàng)建集合 TreeSet<T> treeSet = new TreeSet<>()
- 添加元素:treeSet.add();
- 刪除元素:treeSet.remove();
- 遍歷:1. 增強(qiáng)for 2. 迭代器
- 判斷:treeSet.contains();
補(bǔ)充:TreeSet集合的使用
Comparator 實(shí)現(xiàn)定制比較(比較器)
// 重寫compare,比較姓名和年齡(Person類屬性有姓名和年齡) @override public int compare(Person o1, Person o2){int n1 = o1.getAge()-o2.getAge();int n2 = o1.getName().comareTo(o2.getName());return n1 == 0 ? n2 : n1; }5 Map接口與實(shí)現(xiàn)類
Map接口
作用和特點(diǎn):
- 用于存儲(chǔ)任意鍵值對(key - value)
- 鍵:無序、無下標(biāo)、不允許重復(fù)(唯一)
- 值:無序、無下標(biāo)、允許重復(fù)
方法:
- V put(K key, V value) 將對象存到集合中,關(guān)聯(lián)鍵值。Key重復(fù)則覆蓋鍵值。
- V get(Object key) 根據(jù)鍵獲得對應(yīng)的值
- Collection<V> values() 返回包含所有值的Collection集合
- Set<K> keySet() 返回此Map中包含的鍵的Set視圖。
- Set<Map.Entry<K,V>> entrySet() 返回此Map中包含的映射的Set視圖。
以HashMap為例說明:
//創(chuàng)建Map集合的HashMap對象Map<String, String> map = new HashMap<>(); // 1. 添加元素map.put("cn", "中國");map.put("uk", "英國");map.put("cn", "zhongguo"); // 會(huì)替換第一個(gè) // 2. 刪除map.remove("uk"); // 3. 遍歷 // 3.1 使用keySet()//Set<String> keyset = map.keySet();下一行的map.keyset已經(jīng)有這行代碼的含義 // 所有Key的set集合,尖括號中的是Key的數(shù)據(jù)類型for(String key : map.keySet()){sout(key + "---" + map.get(key)); } // 3.2 使用entrySet()//Set<Map.Entry<String, String>> entries = map.entrySet();同理,下一行的map.entries已經(jīng)表達(dá)for(Map.Entry<String, String> entry : map.entrySet()){sout(entry.getKey() + "---" + entry.getValue(); }Map接口的內(nèi)部接口Entry<K,V>
Interface Map.Entry<K,V>
-
Map鍵值對。 Map.entrySet方法返回Map的集合視圖,其元素屬于此類。
-
獲取對映射鍵值對的引用的唯一方法是從該集合視圖的迭代器。 這些Map.Entry對象僅在迭代期間有效。
-
如果在迭代器返回鍵值對之后已經(jīng)修改了背景映射,則映射鍵值對的行為是未定義的,除非通過映射鍵值對上的setValue操作。
-
常用方法:
K getKey() 返回與此鍵值對相對應(yīng)的鍵。
V getValue() 返回與此鍵值對相對應(yīng)的值。
V setValue(V value) 用指定的值替換與該鍵值對相對應(yīng)的值(可選操作)。 (寫入地圖。)
Map實(shí)現(xiàn)類
- HashMap【重點(diǎn)】:
JDK1.2版本,線程不安全,運(yùn)行效率快。允許用null作為key或是value - Hashtable:
線程安全,運(yùn)行效率慢;不允許null作為key或是value - Properties(詳見IO框架):
Hashtable的子類,要求key和value都是string,通常用于配置文件的讀取 - TreeMap:
實(shí)現(xiàn)了SortedMap接口(Map的子接口),可以對key自動(dòng)排序
HashMap
- 存儲(chǔ)結(jié)構(gòu):哈希表(數(shù)組+鏈表+紅黑樹)
- 使用key可使hashcode和equals作為重復(fù)
- 增、刪、遍歷、判斷與上面一致
源碼分析總結(jié):
HashMap剛創(chuàng)建時(shí),table是null,節(jié)省空間,當(dāng)添加第一個(gè)元素時(shí),table容量調(diào)整為16
當(dāng)元素個(gè)數(shù)大于閾值(16*0.75 = 12)時(shí),會(huì)進(jìn)行擴(kuò)容,擴(kuò)容后的大小為原來的兩倍,目的是減少調(diào)整元素的個(gè)數(shù)
jdk1.8當(dāng)每個(gè)鏈表長度 >8 ,并且數(shù)組元素個(gè)數(shù) ≥64時(shí),會(huì)調(diào)整成紅黑樹,目的是提高效率
jdk1.8當(dāng)鏈表長度 <6 時(shí) 調(diào)整成鏈表
jdk1.8以前,鏈表時(shí)頭插入,之后為尾插入
TreeMap
略
6 泛型與工具類
泛型
- 本質(zhì)是參數(shù)化類型,把類型作為參數(shù)傳遞
- 常見形式有泛型類、泛型接口、泛型方法
- 語法:類名<T> 。T是類型占位符,表示一種引用類型,可以寫多個(gè),在尖括號里用逗號隔開<T,E,K,…>
- 作用:1. 提高代碼重用性;2. 防止類型轉(zhuǎn)換異常,提高代碼安全性
注意: 1. 泛型只能使用引用類型
2. 不同泛型類型對象之間不能相互賦值
泛型接口
- 語法:接口名<T>
- 注意:不能創(chuàng)建泛型靜態(tài)常量
泛型接口實(shí)現(xiàn)有兩種途徑:
一是創(chuàng)建實(shí)現(xiàn)類的時(shí)候就把泛型類型定義好;二是泛型接口的實(shí)現(xiàn)類仍然是泛型,這種的話在創(chuàng)建對象時(shí)必須定義好泛型的類型
第二種途徑在創(chuàng)建對象時(shí)要聲明泛型類型:
MyInterfaceImpl2<Integer> impl2 = new MyInterfaceImpl2<>(); impl2.server();泛型方法
- 語法:<T> 返回值類型
例:
public <T> void show(T t){} public <T> T show(T t){//方法體return t;}調(diào)用
MyGenericMethod myGenericMethod = new MyGenericMethod(); myGenericMethod.show("字符串");// show方法返回值類型自動(dòng)變?yōu)樽址?/span> myGenericMethod.show(200);// integer類型 myGenericMethod.show(3.14);// double類型因此在調(diào)用泛型方法的時(shí)候,數(shù)據(jù)的類型不用傳遞,傳遞的數(shù)據(jù)決定了數(shù)據(jù)的類型
泛型集合
Java允許使用泛型集合類的時(shí)候不傳遞泛型(即使那個(gè)類是泛型類),這時(shí)就是Object類,如LinkedList li = new LinkedList();。意味著可以添加任何類型的數(shù)據(jù),因?yàn)镺bject是所有類的父類。
但是存在的弊端就是,當(dāng)傳遞的數(shù)據(jù)類型很多,到時(shí)要對Object類型強(qiáng)轉(zhuǎn),那么就會(huì)容易在強(qiáng)轉(zhuǎn)的時(shí)候出錯(cuò)。而且如果一個(gè)集合里面有多種數(shù)據(jù)類型的時(shí)候就會(huì)容易出現(xiàn)異常。
- 泛型集合概念:
參數(shù)化類型、類型安全的集合,強(qiáng)制集合元素的類型必須一致 - 特點(diǎn):
編譯時(shí)即可檢查,而非運(yùn)行時(shí)拋出異常;
訪問時(shí),不必類型轉(zhuǎn)換(拆箱);
不同泛型之間引用不能相互賦值,泛型不存在多態(tài)
確定集合的數(shù)據(jù)類型就會(huì)避免上述問題產(chǎn)生,也不存在要對Object類型強(qiáng)轉(zhuǎn)的情況了。如LinkedList<String> li = new LinkedList<String>();
Collections工具類
-
概念:集合工具類,定義了除了存取以外的集合常用方法
-
其他方法 :
copy復(fù)制、reverse反轉(zhuǎn)、shuffle打亂
直接二分查找int i = Collections.binarySearch(list, x); 成功返回索引
補(bǔ)充:
// list轉(zhuǎn)成數(shù)組 Integer[] arr = list.toArray(new Integer[0]);//當(dāng)數(shù)組長度小于list長度時(shí),數(shù)組長度自動(dòng)變?yōu)閘ist的長度,即0自動(dòng)變?yōu)閘ist的長度 sout(arr.length); sout(Array.toString(arr));// 數(shù)組轉(zhuǎn)成集合 // 此時(shí)為受限集合,不能 添加和刪除! String[] name = {"張三","李四","王五"}; List<String> list2 = Arrays.asList(names);// 把基本類型數(shù)組轉(zhuǎn)為集合時(shí),需要修改為包裝類 Integer[] nums = {100, 200, 300, 400, 500}; List<Integer> list3 = Arrays.asList(nums);總結(jié)
以上是生活随笔為你收集整理的Java学习笔记3——集合框架的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: html将excel数据自动导入到网页,
- 下一篇: 分针网——怎么轻松学习JavaScrip