Java集合Set,List和Map等
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Java集合Set,List和Map等
1 Java集合框架
因?yàn)镴ava是面向?qū)ο蟮恼Z言,對事物的體現(xiàn)都是以對象的形式,為了方便對多個(gè)對象的操作,就要對對象進(jìn)行存儲(chǔ)。另一方面,使用Array存儲(chǔ)對象方面具有一些弊端 。Java集合就像一個(gè)容器,可以把多個(gè)對象的引用放入容器中,它們可以幫我們方便地組織和管理一組對象。
數(shù)據(jù)的弊端:①數(shù)組初始化后,就確定長度了(長度不可改變,便于擴(kuò)展)②聲明時(shí)的類型,就決定了進(jìn)行元素初始化時(shí)的類型③提供的屬性和方法少,不便于進(jìn)行添加、刪除、插入等操作,且效率不高,也無法直接獲取存儲(chǔ)元素的個(gè)數(shù)④數(shù)組存儲(chǔ)的數(shù)據(jù)是有序的、可以重復(fù)的(比較單一)。
Java 集合類可以用于存儲(chǔ)數(shù)量不等的多個(gè)對象,還可用于保存具有映射關(guān)系的關(guān)聯(lián)數(shù)組。
Java 集合可以分為兩大集合體系Collection和Map。集合框架圖如下。
2 Collection接口
Collection接口:是單列數(shù)據(jù),定義了存取一組對象的方法和集合。Collection 接口是 List、Set 和 Queue 接口的父接口,該接口里定義的方法 既可用于操作 Set 集合,也可用于操作 List 和 Queue 集合。 在 Java5 之前,Java 集合會(huì)丟失容器中所有對象的數(shù)據(jù)類型,把所有對象都 當(dāng)成 Object 類型處理;從 JDK 5.0 增加了泛型以后,Java 集合可以記住容器中對象的數(shù)據(jù)類型。
set接口:存放無序不可重復(fù)的數(shù)據(jù)。set接口下有HashSet,LinkedHashSet,TreeSet
List接口:存放有序可以重復(fù)數(shù)據(jù)。List接口下有ArrayList,Vector,LinkedList
Collection的常用API:
| API | 描述 |
| ? ? ? ? ? ? ? ? ? ? ? boolean add(E e) | 添加元素 |
| boolean addAll(Collection<? extends E> c) | 添加集合元素 |
| void clear() | 清除集合中的所有元素 |
| boolean remove(Object o) | 刪除集合中的某一個(gè)元素,通過元素的equals方法判斷是否是要?jiǎng)h除的那個(gè)元素 |
| boolean removeAll(Collection<?> c) | 刪除多個(gè)元素,也就是取當(dāng)前集合的差集 |
| boolean isEmpty() | 判斷集合中的元素是否為空 |
| boolean contains(Object o) | 判斷集合中是否包含該元素,是通過元素的equals方法來判斷是否是同一個(gè)對象 |
| boolean containsAll(Collection c) | 也是調(diào)用元素的equals方法來比較的。拿兩個(gè)集合的元素挨個(gè)比較。 |
| Iterator<E> iterator() | 返回迭代器對象,用于集合遍歷 |
| int size() | 獲取集合中元素個(gè)數(shù) |
| Object[] toArray() | 集合轉(zhuǎn)換數(shù)組 |
| Arrays.asList(T… t) | 數(shù)組轉(zhuǎn)換集合 |
?
2.1 List接口
特點(diǎn):有序(存儲(chǔ)順序和取出順序一致),可重復(fù)。
List容器中的元素都對應(yīng)一個(gè)整數(shù)型的序號(hào)記載其在容器中的位置,可以根據(jù)序號(hào)存取容器中的元素。
2.1.1?ArrayList
優(yōu)點(diǎn):底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢。缺點(diǎn):線程不安全,效率高
常用API:
| API | 描述 |
| ? ? ? ? ? ?boolean?add(E e) | 添加單個(gè)元素 |
| void add(int index, E element) | 在指定的下標(biāo)處添加元素 |
| E get(int index) | 通過下標(biāo)來獲取元素 |
| int indexOf(Object o) | 獲取集合某一元素的下標(biāo)(從左到向查找) |
| int lastIndexOf(Object o) | 獲取集合某一元素的下標(biāo)(從右向左查找) |
| boolean remove(Object o) | Collection接口中的方法,根據(jù)元素刪除? |
| E remove(int index) | List接口中的方法,根據(jù)下標(biāo)刪除,E代表返回刪除對象 |
| boolean retainAll(Collection<?> c) | 交集 |
| E set(int index, E element) | 修改某一下標(biāo)對應(yīng)的元素 |
| List<E> subList(int fromIndex, int toIndex) | 返回當(dāng)前集合的一個(gè)子集,從開始下標(biāo)(包含)到結(jié)束下標(biāo)(不包含) |
注意:要?jiǎng)h除int類型要用Integer()方法,因?yàn)閭鱥nt類型的話刪除的得是索引。
本質(zhì)上,ArrayList是對象引用的一個(gè)”變長”數(shù)組 ,在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ù)組 。
Arrays.asList(…) 方法返回的 List 集合,既不是 ArrayList 實(shí)例,也不是 Vector 實(shí)例。 Arrays.asList(…) 返回值是一個(gè)固定長度的 List 集合
2.1.2?LinkedList
優(yōu)點(diǎn):底層數(shù)據(jù)結(jié)構(gòu)是鏈表,查詢慢,增刪快。 缺點(diǎn):線程不安全,效率高
常用API:
| API | 描述 |
| ? ? ? ? ? ?void addFirst(E e) | 添加第一個(gè)位置? |
| void addLast(E e) | 添加在末尾 |
| E getLast() | 獲取最后一個(gè)元素 |
| E getFirst() | 獲取第一個(gè)位置元素 |
| E removeFirst() | 刪除第一個(gè)元素?=>?remove() ?刪除此列表的頭(第一個(gè)元素) |
| E removeLast() | 刪除最后一個(gè)元素 |
LinkedList 是個(gè)雙向鏈表,內(nèi)部沒有聲明數(shù)組,而是定義了Node類型的first和last, 用于記錄首末元素。同時(shí),定義內(nèi)部類Node,作為LinkedList中保存數(shù)據(jù)的基本結(jié)構(gòu)。Node除了保存數(shù)據(jù),還定義了兩個(gè)變量:prev變量記錄前一個(gè)元素的位置,next變量記錄下一個(gè)元素的位置 。
private static class Node<E> {E item;Node<E> next;Node<E> prev;Node(Node<E> prev, E element, Node<E> next) {this.item = element;this.next = next;this.prev = prev;}}2.1.3?Vector
優(yōu)點(diǎn):底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢。? 缺點(diǎn):線程安全,效率低
常用API:void addElement(E obj) ; ???//添加元素的方法。? ? ? int capacity() ; ???????????//默認(rèn)為10
2.1.4 ArrayList,LinkedList,Vector的異同
(1)ArrayList和LinkedList:都是線程不安全的,相對于線程安全的Vector,執(zhí)行效率要高。ArrayList是基于動(dòng)態(tài)數(shù)據(jù)的數(shù)據(jù)結(jié)構(gòu),LinkedList是基于鏈表的數(shù)據(jù)結(jié)構(gòu)。隨機(jī)訪問查詢,ArrayList的效率要比LinkedList高,因?yàn)長inkedList要移動(dòng)指針,對于新增和刪除,LinkedList效率比較高,因?yàn)锳rrayList要移動(dòng)數(shù)據(jù)
(2)ArrayList和Vector:他們幾乎是相同的,唯一的區(qū)別是Vector是同步類,屬于強(qiáng)同步,正常情況下使用ArrayList而不是Vector,因?yàn)橥娇梢杂晌覀冏约嚎刂?。Vector每次擴(kuò)容請求增大2倍空間,ArrayList請求增大1.5倍空間。
?
2.2 Set接口
特點(diǎn):無序(存儲(chǔ)順序和取出順序不一致),唯一
2.2.1 HashSet
底層數(shù)據(jù)結(jié)構(gòu)是哈希表(無序,唯一)。
保證唯一性:依賴hashCode()和equals()方法。使用HashCode算法,獲取對象存儲(chǔ)的位置。如果沒有,就會(huì)將對象存儲(chǔ)在這個(gè)位置。如果有(對象的HashCode一樣),會(huì)調(diào)用equals方法。
如果兩個(gè)對象相同,那么它們的hashCode值一定要相同;如果兩個(gè)對象的hashCode相同,它們并不一定相同。
public class TestHashSet {@Testpublic void test2() {HashSet set = new HashSet();set.add(new Person("小明",20));set.add(new Person("小張",23));set.add(new Person("小明",20)); // set.add("abc"); // System.out.println("abc".hashCode()); // // System.out.println(new String("abc").hashCode()); //System.out.println(set.size()); //輸出2System.out.println(set);} } class Person{String name;int age;@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + age;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (age != other.age)return false;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}}HashSet底層也是數(shù)組,初始容量為16,使用率超過0.75,則擴(kuò)容為原來的2倍。
向HashSet中添加元素的過程:①向HashSet 存入一個(gè)元素,會(huì)調(diào)用該對象的hashCode方法得到hashCode值,根據(jù)這個(gè)hashCode值通過某種散列函數(shù)覺得這個(gè)對象在HashSet 底層數(shù)組中的存儲(chǔ)位置。②如果2個(gè)元素的hashCode值相等,繼續(xù)調(diào)用equals方法,如果equals方法結(jié)果為true,添加失敗;如果為false,那么會(huì)保存該元素,但是該數(shù)組的位置已經(jīng)有元素了,那么會(huì)通過鏈表的方式繼續(xù)鏈接。
總結(jié):hashCode不一樣會(huì)添加元素,不會(huì)驗(yàn)證euqals方法;hashCode一樣會(huì)驗(yàn)證equals方法,如果相同則不會(huì)添加后元素,否則會(huì)添加后元素。
2.2.2 LinkedHashSet
繼承自HashSet,底層數(shù)據(jù)結(jié)構(gòu)是鏈表和哈希表,由鏈表保證元素有序,由哈希表保證元素唯一。根據(jù)元素的 hashCode 值來決定元素的存儲(chǔ)位置。
與hashSet區(qū)別:遍歷時(shí)LinkedHashSet比hashSet效率高;插入和刪除元素hash效率高。
2.2.3?TreeSet
TreeSet 底層數(shù)據(jù)結(jié)構(gòu)是紅黑樹。(唯一,有序)。是 SortedSet 接口的實(shí)現(xiàn)類,TreeSet 可以確保集合元素處于排序狀態(tài)。
特點(diǎn):(1)TreeSet添加元素的類型要一致。
(2)輸出的順序可以按一定的規(guī)則輸出。
(3)排序方式:①自然排序?實(shí)現(xiàn)Comparable接口;②定制排序?實(shí)現(xiàn)Comparator 接口
public class Test1 {//自然排序測試@Testpublic void test() {TreeSet<Employee> tree = new TreeSet<>();tree.add(new Employee("cc",10,new MyDate(2010,1,1)));tree.add(new Employee("ff",10,new MyDate(2011,1,1)));tree.add(new Employee("a",8,new MyDate(2010,1,5)));tree.add(new Employee("e",13,new MyDate(2013,1,1)));tree.add(new Employee("cca",12,new MyDate(2015,5,1)));System.out.println(tree);}//自定義排序測試@Testpublic void test1() {TreeSet<Employee1> tree = new TreeSet<>(new Comparator<Employee1>() {//比較o1和o2的大小:如果方法返回正整數(shù),則表示o1大于o2;如果返回0,表示相等;返回負(fù)整數(shù),表示o1小于o2。@Overridepublic int compare(Employee1 o1, Employee1 o2) {if(o1.getBirthday().getYear() == o2.getBirthday().getYear()) {if(o1.getBirthday().getMonth()==o2.getBirthday().getMonth()) {if(o1.getBirthday().getDay()==o2.getBirthday().getDay()) {return 0;}return o1.getBirthday().getDay()-o2.getBirthday().getDay();}return o1.getBirthday().getMonth()-o2.getBirthday().getMonth();}return o1.getBirthday().getYear() - o2.getBirthday().getYear();}});tree.add(new Employee1("cc",10,new MyDate(2010,1,1)));tree.add(new Employee1("ff",10,new MyDate(2011,1,1)));tree.add(new Employee1("a",8,new MyDate(2010,1,5)));tree.add(new Employee1("e",13,new MyDate(2013,1,1)));tree.add(new Employee1("cca",12,new MyDate(2015,5,1)));System.out.println(tree);} } class Employee implements Comparable<Employee>{private String name;private int age;private MyDate birthday;public Employee() {super();}public Employee(String name, int age, MyDate birthday) {super();this.name = name;this.age = age;this.birthday = birthday;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public MyDate getBirthday() {return birthday;}public void setBirthday(MyDate birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "[name=" + name + ", age=" + age + ", birthday=" + birthday + "]";}@Overridepublic int compareTo(Employee o) {return this.name.compareTo(o.name);}}class MyDate{private int month;private int day;private int year;public MyDate() {}public MyDate(int year, int month, int day) {this.month = month;this.day = day;this.year = year;}public int getMonth() {return month;}public void setMonth(int month) {this.month = month;}public int getDay() {return day;}public void setDay(int day) {this.day = day;}public int getYear() {return year;}public void setYear(int year) {this.year = year;}@Overridepublic String toString() {return "[" +year + "-"+ month + "-" + day + "]";}}class Employee1{private String name;private int age;private MyDate birthday;public Employee1() {super();}public Employee1(String name, int age, MyDate birthday) {super();this.name = name;this.age = age;this.birthday = birthday;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public MyDate getBirthday() {return birthday;}public void setBirthday(MyDate birthday) {this.birthday = birthday;}@Overridepublic String toString() {return "[name=" + name + ", age=" + age + ", birthday=" + birthday + "]";}}3 Map接口
Map接口:雙列數(shù)據(jù),保存具有映射關(guān)系的K-V對的集合。Map接口有三個(gè)比較重要的實(shí)現(xiàn)類,分別是HashMap、TreeMap和HashTable。Map接口和Collection接口是并列的。
Map 中的 key 和 value 都可以是任何引用類型的數(shù)據(jù) 。因?yàn)镸ap 中的 key 用Set來存放,所以不允許重復(fù),即同一個(gè) Map 對象所對應(yīng)的類,須重寫hashCode()和equals()方法。key 和 value 之間存在單向一對一關(guān)系,即通過指定的 key 總能找到唯一的、確定的。
3.1 HashMap
HashMap是 Map 接口使用頻率最高的實(shí)現(xiàn)類。 允許使用null鍵和null值,與HashSet一樣,不保證映射的順序。
所有的key構(gòu)成的集合是Set:無序的、不可重復(fù)的。所以,key所在的類要重寫: equals()和hashCode() 。所有的value構(gòu)成的集合是Collection:無序的、可以重復(fù)的。所以,value所在的類 要重寫:equals() 。
一個(gè)key-value構(gòu)成一個(gè)entry,所有的entry構(gòu)成的集合是Set:無序的、不可重復(fù)的。
HashMap 判斷兩個(gè) key 相等的標(biāo)準(zhǔn)是:兩個(gè) key 通過 equals() 方法返回 true, hashCode 值也相等。HashMap 判斷兩個(gè) value相等的標(biāo)準(zhǔn)是:兩個(gè) value 通過 equals() 方法返回 true。
Map接口常用API如下:
| 添加刪除操作API | 描述 |
| ? ? ? ? ? ? ? ? ? Object put(Object key,Object value)? | 添加元素 |
| Object remove(Object key) | 刪除 |
| void putAll(Map t) | 添加map集合 |
| void clear() ? | 清除 |
| 查詢操作API | 描述 |
| ? ? ? ? ? ? ? ? Object get(Object key) | 通過key獲取vclue |
| boolean containsKey(Object key) | 判斷key在map集合是否存在 |
| boolean containsValue(Object value) | 判斷value在map集合是否存在 |
| int size() ?? | map集合元素的個(gè)數(shù) |
| boolean isEmpty() ??? | 是否為空??如果空返回是true |
| boolean equals(Object obj) | 比較 |
| 集合操作 | 描述 |
| ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?? Set keySet() | 鍵的集合 |
| Collection values() | 值的集合 |
| Set entrySet() | 鍵\值集合 |
注意:如果key相同,后者會(huì)替換前者。與HashSet不同,HashSet相同的話不添加后者
HashMap存儲(chǔ)結(jié)構(gòu)在JDK7以前是:數(shù)組+鏈表,在JDK8后是:數(shù)組+鏈表+紅黑樹
JDK 1.8之前HashMap的存儲(chǔ)結(jié)構(gòu)說明:內(nèi)部存儲(chǔ)結(jié)構(gòu)是數(shù)組和鏈表的結(jié)合。 當(dāng)實(shí)例化一個(gè)HashMap時(shí),系統(tǒng)會(huì)創(chuàng)建一個(gè)長度為Capacity(哈希表中被稱為容量 )的Entry數(shù)組,數(shù)組中可以存放元素的位置稱為“桶(bucket)”,每個(gè)桶有自己的索引,系統(tǒng)可以根據(jù)索引快速的找到桶中的元素。每個(gè)桶存儲(chǔ)一個(gè)元素,即一個(gè)Entry對象,但是每個(gè)Entry對象可以帶一個(gè)引用變量,用于指向下一個(gè)元素。所以在一個(gè)桶中,就有可能生成一個(gè)Entry鏈,新添加的元素作為鏈表的head。
添加元素的過程:①首先計(jì)算entry(key,value)中key的hashCode值,得到在底層Entry數(shù)組中要存儲(chǔ)的位置,如果這個(gè)位置上沒有元素,直接添加成功;如果這個(gè)位置上已經(jīng)存在一個(gè)entry1或者存在一個(gè)entry鏈表了,則循環(huán)比較每一個(gè)entry中你的key和要插入的entry的key,如果hash值不同,添加到entry鏈表;如果hash值相同,再比較equals,如果相同則用待插入的entry的value替換鏈表中與他equals相同的entry的value,如果遍歷一遍以后發(fā)現(xiàn)所有的equals都不相等,則插入鏈表,這個(gè)entry指向原有的entry元素。
HashMap擴(kuò)容:當(dāng)HashMap中的元素越來越多的時(shí)候,因?yàn)閿?shù)組的長度時(shí)固定的,那么hash沖突的概率也越來越高,為了提高查詢效率就需要對數(shù)組進(jìn)行擴(kuò)容。當(dāng) HashMap 中的元素個(gè)數(shù)超過數(shù)組長度的loadFactor (默認(rèn)值是0.75)就會(huì)進(jìn)行擴(kuò)容。默認(rèn)數(shù)組大小DEFAULT_INITIAL_CAPACITY 是16,當(dāng)HashMap中元素個(gè)數(shù)超過16*0.75=12個(gè)時(shí)就進(jìn)行擴(kuò)容,擴(kuò)大一倍,即為32。在HashMap數(shù)組擴(kuò)容之后,最消耗性能的點(diǎn)就是原數(shù)組中的數(shù)據(jù)必須重新計(jì)算其在新數(shù)組中的位置并插入。所以如果我們已經(jīng)預(yù)知HashMap中元素的個(gè)數(shù),預(yù)設(shè)元素的個(gè)數(shù)能有效提高HashMap的性能
JDK 1.8之后HashMap的存儲(chǔ)結(jié)構(gòu)說明:內(nèi)部存儲(chǔ)結(jié)構(gòu)是數(shù)組+鏈表+紅黑樹,當(dāng)實(shí)例化一個(gè)HashMap的時(shí)候,會(huì)初始化initialCapacity和loadFactor,在插入第一個(gè)entry的時(shí)候,系統(tǒng)創(chuàng)建一個(gè)長度為initialCapacity的Node數(shù)組,數(shù)組中可以存放元素的位置稱為“桶(bucket)”,每個(gè)桶有自己的索引,系統(tǒng)可以根據(jù)索引快速的找到桶中的元素。每個(gè)桶存儲(chǔ)一個(gè)元素,即一個(gè)Node對象,但是每個(gè)Node對象可以帶一個(gè)引用變量,用于指向下一個(gè)元素。所以在一個(gè)桶中,就有可能生成一個(gè)Node鏈。也由可能是一個(gè)個(gè)TreeNode對象,每個(gè)TreeNode對象有兩個(gè)葉子節(jié)點(diǎn)left和right。新添加的元素就可能作為鏈表的最后一個(gè)或者樹的葉子節(jié)點(diǎn)。
HashMap擴(kuò)容:當(dāng)HashMap中的元素越來越多的時(shí)候,因?yàn)閿?shù)組的長度時(shí)固定的,那么hash沖突的概率也越來越高,為了提高查詢效率就需要對數(shù)組進(jìn)行擴(kuò)容。當(dāng) HashMap 中的元素個(gè)數(shù)超過數(shù)組長度的loadFactor (默認(rèn)值是0.75)就會(huì)進(jìn)行擴(kuò)容。默認(rèn)數(shù)組大小DEFAULT_INITIAL_CAPACITY 是16,當(dāng)HashMap中元素個(gè)數(shù)超過16*0.75=12個(gè)時(shí)就進(jìn)行擴(kuò)容,擴(kuò)大一倍,即為32。在HashMap數(shù)組擴(kuò)容之后,最消耗性能的點(diǎn)就是原數(shù)組中的數(shù)據(jù)必須重新計(jì)算其在新數(shù)組中的位置并插入。
HashMap樹形化:①當(dāng)HashMap中其中一個(gè)鏈的對象個(gè)數(shù)達(dá)到了8個(gè),如果Capacity還沒有到64,會(huì)進(jìn)行擴(kuò)容解決。②如果Capacity已經(jīng)到64那么這個(gè)鏈表會(huì)變成樹,節(jié)點(diǎn)的類型也有Node變成TreeNode類型。如果當(dāng)映射關(guān)系被移除后,下次resize方法時(shí)判斷樹的結(jié)點(diǎn)個(gè)數(shù)低于6個(gè),也會(huì)把樹再轉(zhuǎn)為鏈表。
JDK 1.8之后HashMap與JDK 1.8之前HashMap的比較:①JDK 1.8默認(rèn)情況下,先不創(chuàng)建長度為16的數(shù)組,只有在第一次插入數(shù)據(jù)的時(shí)候才創(chuàng)建長度為16的數(shù)組 ②數(shù)組為Node類型,在JDK 1.7中稱為Entry類型 ③JDK 1.8形成鏈表結(jié)構(gòu)時(shí),新添加的key-value對在鏈表的尾部(七上八下) ④當(dāng)數(shù)組指定索引位置的鏈表長度>8時(shí),且map中的數(shù)組的長度> 64時(shí),此索引位置上的所有key-value對使用紅黑樹進(jìn)行存儲(chǔ)。
?loadFactor負(fù)載因子的值對HashMap的影響:負(fù)載因子的大小決定了HashMap的數(shù)據(jù)密度,負(fù)載因子越大發(fā)碰撞的概率就越大,導(dǎo)致鏈表長度越長,造成查詢和插入時(shí)比較的次數(shù)越多,性能下降;負(fù)載因子越小,數(shù)據(jù)密度越小,就越容易觸發(fā)擴(kuò)容,碰撞的概率越小,數(shù)組中鏈表越短,查詢和插入時(shí)比較的次數(shù)會(huì)減少,性能更高,但是會(huì)浪費(fèi)一定的內(nèi)存空間,并且經(jīng)常擴(kuò)容對性能也有影響。初始化可以預(yù)設(shè)大一點(diǎn)。
3.2 LinkedHashMap
在HashMap存儲(chǔ)結(jié)構(gòu)的基礎(chǔ)上,使用了一對雙向鏈表來記錄添加 元素的順序 。與LinkedHashSet類似,LinkedHashMap 可以維護(hù) Map 的迭代,存儲(chǔ)順序和輸出順序一致。
public class TestLinkedHashMap{@Testpublic void test2(){LinkedHashMap link = new LinkedHashMap();link.put("aa", 90); link.put("cc",88);link.put(new Date(),99);link.put(null, null);//keysetSet keys = link.keySet();for(Object o : keys) {System.out.println(o+"===="+link.get(o));}} }3.3 TreeMap
TreeMap存儲(chǔ) Key-Value 對時(shí),需要根據(jù) key-value 對進(jìn)行排序 ,按照添加的key屬性排序,TreeSet底層使用紅黑樹結(jié)構(gòu)存儲(chǔ)數(shù)據(jù)。
自然排序:實(shí)現(xiàn)接口Comparable重寫int CompareTo(Object obj)方法;
定制排序:實(shí)現(xiàn)接口Comparator重寫int CompareTo(Object obj1,Object obj2)方法;
import java.util.Comparator; import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap; import org.junit.Test;public class TestTreeMap {@Testpublic void test2() {Comparator com = new Comparator() {@Overridepublic int compare(Object o1, Object o2) {if(o1 instanceof Person && o2 instanceof Person) {Person p1 = (Person)o1;Person p2 = (Person)o2;return p1.name.compareTo(p2.name);}return 0;}};Map tree =new TreeMap(com);tree.put(new Person("a"),90);tree.put(new Person("e"),30);tree.put(new Person("d"),50);tree.put(new Person("c"),70);Set set = tree.keySet();Iterator it = set.iterator();while(it.hasNext()) {it.next();}System.out.println(tree);}//自然排序@Testpublic void test1() {TreeMap tree =new TreeMap();tree.put(new Person("a"),90);tree.put(new Person("e"),30);tree.put(new Person("d"),50);tree.put(new Person("c"),70);System.out.println(tree);} } class Person1 {String name;public Person1(String name) {this.name = name;} @Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}@Overridepublic String toString() {return "Person [name=" + name + "]";}} class Person implements Comparable{String name;public Person(String name) {super();this.name = name;}@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + ((name == null) ? 0 : name.hashCode());return result;}@Overridepublic boolean equals(Object obj) {if (this == obj)return true;if (obj == null)return false;if (getClass() != obj.getClass())return false;Person other = (Person) obj;if (name == null) {if (other.name != null)return false;} else if (!name.equals(other.name))return false;return true;}@Overridepublic int compareTo(Object o) {if(o instanceof Person) {Person p = (Person)o;return this.name.compareTo(p.name);}return 0;}@Overridepublic String toString() {return "Person [name=" + name + "]";} }3.4?HashTable
與HashMap相同不能保證順序,key值相同替換,但是他是線程安全的。
Hashtable實(shí)現(xiàn)原理和HashMap相同,功能相同。底層都使用哈希表結(jié)構(gòu),查詢速度快,很多情況下可以互用。與HashMap不同,Hashtable 不允許使用 null 作為 key 和 value。
它的子類properties用來操作屬性文件,如下
public void TestProperties throws FileNotFoundException, IOException {public static void main(String[] args){//創(chuàng)建屬性文件類的對象Properties pro = new Properties();//以流的方式讀取文件到內(nèi)存pro.load(new FileInputStream(new File("jdbc.properties")));String name = pro.getProperty("jdbc.username");String password = pro.getProperty("jdbc.password");System.out.println(name+ "--" + password);} }3.5?Properties
Properties 類是 Hashtable 的子類,該對象用于處理屬性文件。因?yàn)閷傩晕募锏?key、value 都是字符串類型,所以 Properties 里的 key 和 value 都是字符串類型。存取數(shù)據(jù)時(shí),建議使用setProperty(String key,String value)方法和 getProperty(String key)方法 。
Properties pros = new Properties();pros.load(new FileInputStream("test.properties"));String user = pros.getProperty("user");System.out.println(user);4?Collections工具類
Collections工具類是一個(gè)操作Set,List和Map等集合的工具類,Collections提供了一系列靜態(tài)的方法對集合中的元素進(jìn)行排序,查詢和修改等操作,還提供了對集合對象設(shè)置不可變,實(shí)現(xiàn)同步控制等方法。
| 方法 | 描述 |
| reverse(List) | 反轉(zhuǎn)List中元素的順序 |
| sort(List) | 根據(jù)元素的自然排序?qū)χ付↙ist集合元素按升序排序 |
| sort(List,Comparator) | 根據(jù)指定的Comparator產(chǎn)生的順序?qū)ist集合元素進(jìn)行排序 |
| swap(List,int,int) | 將指定List集合中的i處元素和j處元素進(jìn)行交換 |
| shuffle(List) | 對List集合元素進(jìn)行隨機(jī)排序 |
| int frequency(Collection,Object) | 返回指定集合中指定元素的出現(xiàn)次數(shù) |
| Object max(Collection) | 根據(jù)元素的自然排序,返回給定集合中的最大元素 |
| Object max(Collection,Comparator) | 根據(jù)Comparator指定的順序,返回給定集合中的最大元素 |
| Object min(Collection) | 根據(jù)元素的自然排序,返回給定集合中的最小元素 |
| Object min(Collection,Comparator) | 根據(jù)Comparator指定的順序,返回給定集合中的最小元素 |
| void copy(List dest,List src) | 將src中的內(nèi)容復(fù)制到dest中 |
| boolean replaceAll(List list, Object oldVal,Object newVal ) | 使用新值替換 List 對象的所有舊值 |
ListArrays.asList(T...t) 數(shù)組轉(zhuǎn)集合? ? ? ? list.toArray(集合轉(zhuǎn)數(shù)組)? ? ?Arrays.sort(array)數(shù)組排序
盡量不要使用ListArrays.asList(T...t) 數(shù)組轉(zhuǎn)集合,因?yàn)樵摲椒ǚ祷毓潭ㄩL的List,不支持add和remove操作,該方法返回的List與傳入的數(shù)組是映射關(guān)系,set/get直接操作數(shù)組,List也會(huì)改變。有以下替代方案:
| Integer[] array = {1,2}; List<Integer>?list = new ArrayList<>(Arrays.asList(array)); |
| List<Integer>?list = new ArrayList<>(); Integer[] array = {1,2}; Collections.addAll(list,array); |
| int[] array = {1,2}; List<integer> list = Arrays.stream(array).bosxed().collect(Collectors.toList()); |
4?Iterator迭代器接口
Iterator對象成為迭代器,是設(shè)計(jì)模式的一種,主要作用就是用于遍歷collection集合中的元素。
迭代器模式的定義為:提供一種方法訪問一個(gè)容器(container)對象中各個(gè)元素,而又不需暴露該對象的內(nèi)部細(xì)節(jié)。迭代器模式,就是為容器而生。
Collection接口繼承了java.lang.Iterable接口,這個(gè)接口有個(gè)iterator方法,所以所有實(shí)現(xiàn)了Collection接口的集合類都有一個(gè)iterator方法。
iterator僅僅用于遍歷集合,iterator本身不提供承載對象的能力,所以創(chuàng)建Iterator對象,必須由一個(gè)被迭代的集合。集合對象每次調(diào)用iterator方法都得到一個(gè)全新的迭代對象,默認(rèn)游標(biāo)都在集合的第一個(gè)元素之前
4.1?Iterator接口的方法
| 方法 | 描述 |
| hasNext() | 如果iterator還有元素則返回true,否則返回false(注意,這時(shí)上面的那個(gè)指針位置不變) |
| next() | 返回這個(gè)iterator的下一個(gè)元素,同時(shí)上面的指針向后移動(dòng)一位。 |
| remove | 刪除 iterator 內(nèi)指針的前1個(gè)元素,前提是至少執(zhí)行過1次next(); |
注意:在調(diào)用next方法之前必須要調(diào)用hasNext方法檢測,否則如果下一條沒有記錄,調(diào)用next則會(huì)拋異常
總結(jié)
以上是生活随笔為你收集整理的Java集合Set,List和Map等的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java增强之并发编程
- 下一篇: Java入门篇 2021/02/22