万字长文带你回顾Java集合框架
目錄
1 Collection
1.1 List
1.1.1 AarrayList
1.1.2 Vector
1.1.3 LinkedList
1.2 Set
1.2.1 HashSet
1.2.2 TreeSet
2 Map
2.1 HashMap
2.2 Hashtable
2.3 TreeMap
3 Iterator
4 其他集合遍歷輸出的方法
4.1 for循環遍歷
4.2 foreach循環遍歷
4.3 Enumeration
Java集合框架中有三大頂層接口:存儲單值的最大父接口Collection,存儲雙值的最大父接口Map,迭代器Iterator,所有類集都定義在java.util包中,可以直接導包:import java.util.*。
1 Collection
Collection接口的定義為:public interface Collection<E> extends Iterable<E>,可見它是可迭代的。接口中定義了 add() addAll() clear() contains() containsAll() isEmpty() iterator() remove() removeAll() retianAll() size() toArray() toArray(T[] a) equals() hashCode() 等15種方法。
JDK1.2之后,一般不直接使用Collection,而是使用其操作的子接口:List 和 Set,子接口下面有實現類。層級關系如下圖所示。
1.1 List
List接口的定義為:public interface List<E> extends Collection<E>,元素允許重復。常用的實現類包括ArrayList、Vector和LinkedList。
List接口擴充的方法有:add() addAll() get() indexOf() lastIndexOf() listIterator() remove() set() subList(),其中涉及元素增刪改查的方法均用索引定位元素,第一個參數都是索引。
1.1.1 AarrayList
ArrayList的定義是:
public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, SerializableAbstractList為List的抽象子類。ArrayList支持快速隨機訪問,可以被克隆,可以被序列化。只要內存夠大,可以無限往里面添加元素。
代碼示例:
import java.util.ArrayList; import java.util.List;public class ArrayListDemo {public static void main(String[] args) {List<String> myList = new ArrayList<>();// 增myList.add("Sun"); // 這是Collection中的add()myList.add(0, "Moon"); // 這是List中的add()myList.add("Earth");myList.add(myList.size(), "Mars"); // size()是Collection的方法,獲取ArrayList的大小System.out.println(myList); // 輸出: [Moon, Sun, Earth, Mars]// 打印時自動調用toString()方法,所以能顯示出元素的具體值// 刪myList.remove(1); // 根據索引刪除元素myList.remove("Moon"); // 根據元素值刪除元素System.out.println(myList); // 輸出:[Earth, Mars]// 查System.out.println(myList.get(1)); // List的方法,根據索引獲得元素值// 改myList.set(0, "Mercury"); // 修改指定索引中的元素值System.out.println(myList);} }1.1.2 Vector
Vector的定義是:
public class Vector<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, SerializableVector的定義和操作方法和ArrayList沒有區別,畢竟都是List接口的實現類,操作以共同的接口為準。
Vector早在JDK1.0就已推出,是Java最早的操作動態數組的類。JDK1.2推出了java類的集合框架后,仍然保留了這個類,并進行了升級,讓其多實現了一個List接口。相比于ArrayList,除了支持Iterator、ListIterator輸出,還支持Enumeration輸出,代碼案例見 3.3 。另外,Vector采用同步處理,性能低于采用異步處理的ArrayList。
代碼示例:
import java.util.Vector;public class VectorDemo1 {public static void main(String[] args) {Vector<String> myVector = new Vector<>();// 增myVector.add("Sun");myVector.add(0,"Moon");myVector.add("Earth");myVector.add(myVector.size(), "Mars");System.out.println(myVector); // 輸出:[Moon, Sun, Earth, Mars]// 刪myVector.remove("Sun");myVector.remove(0);System.out.println(myVector); // 輸出:[Earth, Mars]// 查System.out.println(myVector.get(1)); // 輸出:Mars// 改myVector.set(0, "Mercury");System.out.println(myVector); // 輸出:[Mercury, Mars]1.1.3 LinkedList
LinkedList的定義是:
public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Queue<E>, Cloneable, Serializable該類為鏈表類,使用頻率非常低,既是List接口的子類,也是Queue接口的子類。
Queue中定義的方法包括:add() element() offer() peak() poll() remove()
代碼示例:
import java.util.LinkedList; import java.util.List; import java.util.Queue;public class LinkedListDemo {public static void main(String[] args) {Queue<String> myLink = new LinkedList<>();// 增myLink.add("Sun"); // add():如果有容量限制且已滿,會拋出異常myLink.add("Moon");myLink.offer("Earth"); // offer():如果有容量限制且已滿,會返回falsemyLink.offer("Mars");System.out.println(myLink); // 輸出:[Sun, Moon, Earth, Mars]// 刪myLink.remove("Sun"); // 僅刪除元素System.out.println(myLink); // 輸出:[Moon, Earth, Mars]String ele = myLink.poll(); // poll():刪除并取出頭元素System.out.println(ele); // 輸出:MoonSystem.out.println(myLink); // 輸出:Earth// 查String ele1 = myLink.peek(); // peak():取出頭元素,不刪除,隊列為空拋出異常System.out.println(ele1); // 輸出:EarthString ele2 = myLink.element(); // element():取出頭元素,不刪除,隊列為空返回nullSystem.out.println(ele2); // 輸出:Earth} }?
1.2 Set
Set接口的定義為:public interface Set<E> extends Collection<E>。和List相比,最大的區別在于Set中的元素不允許重復。另外,Set也沒有擴充新的方法,只能調用繼承自Collection的方法,沒有get(int index)方法,也不能循環輸出。
Set有兩個常用子類:HashSet和TreeSet。對于內部的元素,前者為散列存放,后者為排序存放。
1.2.1 HashSet
HashSet的定義為:
public class HashSet<E> extends AbstractSet<E>implements Set<E>, Cloneable, SerializableAbstractSet是Set的抽象類。HashSet的元素為散列存放,元素沒有索引,內部是無序的。
雖然Set本身不能被直接遍歷,但可以利用Collection接口中定義的toArray()方法,轉換為數組。
代碼示例:
import java.util.HashSet; import java.util.Set;public class HashSetDemo {public static void main(String[] args) {Set<String> mySet = new HashSet<>();mySet.add("Sun");mySet.add("Moon");mySet.add("Earth");mySet.add("Sun"); // 不能被添加,因為值為Sun的元素已經存在,元素值不可重復System.out.println(mySet);// 輸出:[Earth, Moon, Sun],與添加時順序并不一致// 轉換為數組后循環遍歷String[] myArray2 = mySet.toArray(String[]::new);// 這種寫法也對: mySet.toArray(new String[] {})for(int i=0;i<mySet.size();i++) {System.out.println(myArray2[i]);}} }對于自定義的類,如果不定義hashCode()和equals()方法,實例化的對象進入HashSet中不能實現去重。去重的前提是要判斷兩個元素是否相等。hashCode()和equals()分別提供了一種判斷方式,hashCode()判斷兩個對象的編碼是否相等,equals()判斷對象中的每個屬性是否相等,如果兩種方法判斷出來的結果都相等,那么認為是重復元素。
代碼示例:
Human2類(還有寫了一個Human類,為了對比,沒有定義hashCode()和equals()方法,為節省篇幅,不在此列出)
import java.util.Objects;public class Human2 {private String name;private int age;public Human2(String name, int age) {this.name = name;this.age = age;}@Overridepublic String toString() {return "name='" + name + ' ' + "age=" + age;}@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Human2 human2 = (Human2) o;return age == human2.age && Objects.equals(name, human2.name);}@Overridepublic int hashCode() {return Objects.hash(name, age);} }HashSetDemo2.java:在HashSet中驗證去重效果
import java.util.HashSet; import java.util.Set;public class HashSetDemo2 {public static void main(String[] args) {Set<Human> mySet = new HashSet<>();mySet.add(new Human("Anna", 20));mySet.add(new Human("Betty", 22));mySet.add(new Human("Cindy", 24));mySet.add(new Human("Cindy", 24));System.out.println(mySet); // 重復元素仍在Set里面,并沒有實現去重/*** 輸出:[name='Anna age=20, name='Cindy age=24, name='Cindy age=24, name='Betty age=22]*/Set<Human2> mySet2 = new HashSet<>();mySet2.add(new Human2("Anna", 20));mySet2.add(new Human2("Betty", 22));mySet2.add(new Human2("Cindy", 24));mySet2.add(new Human2("Cindy", 24));System.out.println(mySet2); // 在類中定義了hashCode()和equals()方法后,實現了去重// 輸出:[name='Anna age=20, name='Cindy age=24, name='Betty age=22]} }1.2.2 TreeSet
TreeSet的定義為:
public class TreeSet<E> extends AbstractSet<E>implements NavigableSet<E>, Cloneable, Serializable再看NavigableSet的定義:
public interface NavigableSet<E> extends SortedSet<E>再看SortedSet的定義:
public interface SortedSet<E> extends Set<E>由此可以清晰地看出這樣一個繼承/實現關系:
需要注意的是,TreeSet添加元素的過程仍然是無序的,實現排序的前提是使用者定義好排序規則,這就需要在自定義的類中實現Comparable接口,并重寫compareTo()方法。 ?
重寫compareTo()方法時,不能以有可能出現相同值的屬性作為唯一的排序標準,否則一旦出現相同值,兩個對象就會被認為是同一個,由于Set元素的不可重復性,其中一個會被丟棄。
代碼示例1:自定義類中定制排序規則
import java.util.Objects;public class Person implements Comparable<Person> {private String name;private int age;public Person(String name, int age) {this.name = name;this.age = age;}@Overridepublic int compareTo(Person o) {// 在這個方法里定制排序規則,這里實現了按年齡升序排序,年齡一致就按姓名排序if(this.age > o.age){return 1;}else if(this.age < o.age){return -1;}else{// 如果return 0,即將年齡作為唯一的排序標準,一旦年齡相同,就會被識別為重復元素return this.name.compareTo(o.name);}}@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +'}';} }代碼示例2:TreeSet實現排序
import java.util.HashSet; import java.util.Set; import java.util.TreeSet;public class TreeSetDemo2 {public static void main(String[] args) {Set<Person> personSet = new TreeSet<>();personSet.add(new Person("Peter",30));personSet.add(new Person("Adam",32));personSet.add(new Person("Spencer",35));System.out.println(personSet);輸出結果為:[Person{name='Peter', age=30}, Person{name='Adam', age=32}, Person{name='Spencer', age=35}]
2 Map
Map接口的定義為:public interface Map<K,V>。Map的含義是映射,內部存儲具有映射關系的鍵值對。
鍵值對又被稱為二元偶對象,其中鍵(Key)不允許重復,值(Value)允許重復。
Map中定義的常用方法包括clear() containsKey() containsValue() entrySet() get() isEmpty() keySet() values() put() putAll() putAll() remove()
取出(get)和刪除(remove)元素的方法的參數都是鍵,即根據鍵獲取值或刪除鍵值對。由于鍵的不可重復性,鍵和鍵值對只能轉化為Set對象;由于值允許重復,因此能夠轉化為Collection對象。由Map轉化過來的Collection對象與Map對象共享一塊內存,改變Collection,Map也會產生相應的改變。
Map接口包括三個子類:HashMap、Hashtable、TreeMap.
2.1 HashMap
HashMap的定義為:
public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable?該子類繼承了Map的抽象子類AbstractMap,可以被克隆和被序列化。只要內存夠大,可以無限往里面添加元素。
HashMap中的元素是無序的。
代碼示例:
import java.util.*;public class HashMapDemo {public static void main(String[] args) {Map<Integer, String> myMap = new HashMap<>();// 增myMap.put(1, "Anna");myMap.put(2, "Bob");myMap.put(3, "Cindy");myMap.put(4, "David");myMap.put(5, "Ellen");System.out.println(myMap); // 輸出:{1=Anna, 2=Bob, 3=Cindy, 4=David, 5=Ellen}// 刪myMap.remove(4); // 根據 鍵 刪除鍵值對System.out.println(myMap); // 輸出:{1=Anna, 2=Bob, 3=Cindy, 5=Ellen}// 想要按 值 刪除,需將所有的值先轉換成Collection,再操作CollectionCollection<String> collection = myMap.values();collection.remove("Anna"); // 按 值 刪除System.out.println(myMap); // 輸出:[Bob, Cindy, Ellen]// 查String value = myMap.get(3); // 根據 鍵 查找值System.out.println(value); // 輸出:Cindy// 將所有的 鍵 轉換為Set 并打印Set<Integer> keys = myMap.keySet();System.out.println(keys); // 輸出:[2, 3, 5]// 將所有的 值 轉換為Collection 并打印Collection<String> values = myMap.values();System.out.println(values); // 輸出:[Bob, Cindy, Ellen]// 獲取 Map 的大小System.out.println(myMap.size()); // 輸出:4// 改myMap.put(2,"Bobby"); // put()方法中傳入已有的 鍵 即可直接實現 值 的修改System.out.println(myMap); // 輸出:{2=Bobby, 3=Cindy, 5=Ellen} }?
2.2 Hashtable
Hashtable的定義為:
public class Hashtable<K,V> extends Dictionary<K,V>implements Map<K,V>, Cloneable, SerializableHashtable繼承了Dictionary類,即字典,定義如下:
class Dictionary<K,V>Hashtable是最早的鍵值對操作類,JDK1.0就已推出,基本操作和HashMap類似,內部元素是無序的。相比于JDK1.2才出現的新操作類HashMap,Hashtable采用同步處理方式,性能較低,而且不允許null值。
代碼示例:
import java.util.Hashtable; import java.util.Map;public class HashtableDemo {public static void main(String[] args) {Map<Integer, String> myMap = new Hashtable<>();myMap.put(1, "Anna");myMap.put(2, "Bob");myMap.put(3, "Cindy");myMap.put(4, "David");myMap.put(5, "Ellen");System.out.println(myMap); // 輸出:{5=Ellen, 4=David, 3=Cindy, 2=Bob, 1=Anna}// 增刪查操作與HashMap一致,不再演示2.3 TreeMap
TreeMap的定義為:
public class TreeMap<K,V> extends AbstractMap<K,V>implements NavigableMap<K,V>, Cloneable, SerializableTreeMap繼承自Map的抽象子類AbstractMap,實現了NvigableMap接口,用于排序,可以被克隆和序列化。
再看NvigableMap的定義:
public interface NavigableMap<K,V> extends SortedMap<K,V>再看SortedMap的定義:
public interface SortedMap<K,V> extends Map<K,V>繼承/實現關系如下:
代碼示例:
import java.util.Iterator; import java.util.Map; import java.util.Set; import java.util.TreeMap;public class TreeMapDemo1 {public static void main(String[] args) {// 按照 鍵 排序,默認升序Map<Integer, String> myMap = new TreeMap<>();myMap.put(2, "Anna");myMap.put(3, "Bob");myMap.put(1, "Cindy");System.out.println(myMap); // 輸出:{1=Cindy, 2=Anna, 3=Bob}} }?
鍵也可以是自定義的類,前提是必須實現Comparable接口,重寫comparableTo()方法定制排序規則。比如鍵為一個餐廳類,鍵值對按評分降序排序,值為按照評分獲取的推薦度。
代碼示例:
Canteen.java:定義一個Canteen類
public class Canteen implements Comparable<Canteen> {private String name;private int score;public Canteen(String name, int score) {this.name = name;this.score = score;}@Overridepublic int compareTo(Canteen canteen) {if (this.score < canteen.score) {return 1;}else if (this.score > canteen.score) {return -1;}else {return this.name.compareTo(canteen.name);}}@Overridepublic String toString() {return "Canteen{" +"name='" + name + '\'' +", score=" + score +'}';}public String recommend(int score) {if (score >=9) {return "強烈推薦";}else if (score >=5) {return "推薦";}else {return "不推薦";}}public int getScore() {return score;} }?TreeMap.java:展示排序結果
package kaikeba2;import java.util.Map; import java.util.TreeMap;public class TreeMapDemo2 {public static void main(String[] args) {// 先創建幾個Canteen的對象Canteen can1 = new Canteen("麥德基",3);Canteen can2 = new Canteen("華萊士",7);Canteen can3 = new Canteen("肯德基", 10);Canteen can4 = new Canteen("麥當勞", 9);// 將這幾個類存到Map中,存放時不是降序的Map<Canteen, String> myMap = new TreeMap<>();myMap.put(can1, can1.recommend(can1.getScore()));myMap.put(can2, can2.recommend(can2.getScore()));myMap.put(can3, can3.recommend(can3.getScore()));myMap.put(can4, can4.recommend(can4.getScore()));// 打印myMap,觀察排序效果System.out.println(myMap);} }運行結果:{Canteen{name='肯德基', score=10}=強烈推薦, Canteen{name='麥當勞', score=9}=強烈推薦, Canteen{name='華萊士', score=7}=推薦, Canteen{name='麥德基', score=3}=不推薦}
3 Iterator
Iterator包含一個子接口ListIterator,這是集合遍歷輸出的首選接口,利用Collection中的iterator()方法將集合轉化為迭代器,然后通過迭代器遍歷元素。
Iterator接口定義為:public interface Iterator<E>,用于迭代一個集合,從而實現集合的遍歷。
定義了三個方法:hasNext() next() remove()
遍歷的原理是:判斷當前元素是否具有下一個元素,有就輸出,如此循環,直到下一個元素為null。
ListIterator接口的定義為:public interface ListIterator<E> extends Iterator<E>,能夠實現雙向輸出
代碼示例1:Iterator
import java.util.ArrayList; import java.util.Collection; import java.util.Iterator;public class IteratorDemo {public static void main(String[] args) {Collection<String> myList = new ArrayList<>();myList.add("Sun");myList.add("Moon");myList.add("Earth");// 用Collection自帶的iterator()方法將 集合 轉化為 迭代器Iterator<String> myIter = myList.iterator();while (myIter.hasNext()) { // 判斷下一個元素是否存在String ele = myIter.next(); // 取出下一個元素System.out.println(ele);if(ele.equals("Earth")) {myIter.remove(); // 刪除元素時必須調用定義在Iterator里面的方法// myList.remove(); 這個操作是錯誤的}}System.out.println(myList); // 輸出:[Sun, Moon],Eearth被刪掉了} }?代碼示例2:ListIterator
import java.util.ArrayList; import java.util.List; import java.util.ListIterator;public class ListIteratorDemo {public static void main(String[] args) {List<String> myList = new ArrayList<>();myList.add("Sun");myList.add(0, "Moon");myList.add("Earth");ListIterator<String> myIter = myList.listIterator();// 從前向后輸出while(myIter.hasNext()) {System.out.println(myIter.next());}System.out.println("-------------------------");// 從后向前輸出while(myIter.hasPrevious()){System.out.println(myIter.previous());}// 反向遍歷之前必須先實現一次正向遍歷,否則無法實現} }4 其他集合遍歷輸出的方法
4.1 for循環遍歷
只有List類能直接用for循環遍歷輸出,Set類不能被直接遍歷。
import java.util.ArrayList; import java.util.List;public class ArrayListDemo2 {public static void main(String[] args) {List<String> myList = new ArrayList<>();myList.add("Sun"); myList.add("Moon"); myList.add("Earth");for(int i=0;i<myList.size();i++) {System.out.println(myList.get(i));}} }Collection類都能轉化為數組。對于不能直接遍歷的Set,可以采用這種方法。
import java.util.HashSet; import java.util.Set;public class HashSetDemo {public static void main(String[] args) {Set<String> mySet = new HashSet<>();mySet.add("Sun");mySet.add("Moon");mySet.add("Earth");mySet.add("Sun"); // 不能被添加,因為值為Sun的元素已經存在,元素值不可重復System.out.println(mySet);// 輸出:[Earth, Moon, Sun],與添加時順序并不一致// 轉換為數組后循環遍歷String[] myArray2 = mySet.toArray(String[]::new);// 這種寫法也對: mySet.toArray(new String[] {})for(int i=0;i<mySet.size();i++) {System.out.println(myArray2[i]);}} }4.2 foreach循環遍歷
foreach可以用于遍歷所有Collection集合,不僅是List,Set也能foreach遍歷
import java.util.HashSet; import java.util.Set;public class ForeachDemo1 {public static void main(String[] args) {// 遍歷ListList<String> myList = new ArrayList<>();myList.add("Sun");myList.add(0, "Moon");myList.add("Earth");myList.add(myList.size(), "Mars");for(String ele : myList){System.out.println(ele);}// 遍歷SetSet<String> mySet = new HashSet<>();mySet.add("Sun");mySet.add("Moon");mySet.add("Earth");mySet.add("Sun");for (String ele:mySet) {System.out.println(ele);}} }4.3 Enumeration
Enumeration的含義是枚舉,只能用于操作Vector,這一傳統接口現在已經被迭代器取代,操作和迭代器Iterator類似。遍歷前,用elements()將Vector轉換為Enueration。
import java.util.Enumeration; import java.util.Vector;public class EnumerationDemo1 {public static void main(String[] args) {Vector<String> myVector = new Vector<>();myVector.add("Sun");myVector.add(0,"Moon");myVector.add("Earth");myVector.add(myVector.size(), "Mars");// 實例化一個Enumeration對象,將Vector轉換為EnumerationEnumeration<String> myEnu = myVector.elements();while(myEnu.hasMoreElements()) {System.out.println(myEnu.nextElement());}} }?
總結
以上是生活随笔為你收集整理的万字长文带你回顾Java集合框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [面经]春季跳槽面筋总结 [2018年3
- 下一篇: 自觉培养“舆商” 争做成功网商