ArrayListjava
LinkedList算法
HashSet數組
LinkedHashSet併發
TreeSetide
咱們掌握了Collection接口的使用後,再來看看Collection接口中的子類,他們都具有那些特性呢?學習
接下來,咱們一塊兒學習Collection中的經常使用幾個子類(List集合、Set集合)測試
查閱API,看List的介紹。有序的 collection(也稱爲序列)。此接口的用戶能夠對列表中每一個元素的插入位置進行精確地控制。用戶能夠根據元素的整數索引(在列表中的位置)訪問元素,並搜索列表中的元素。與 set 不一樣,列表一般容許重複的元素ui
看完API,總結:this
List接口:spa
它是一個元素存取有序的集合。例如,存元素的順序是十一、2二、33。那麼集合中,元素的存儲就是按照十一、2二、33的順序完成的)
它是一個帶有索引的集合,經過索引就能夠精確的操做集合中的元素(與數組的索引是一個道理)
集合中能夠有重複的元素,經過元素的equals方法,來比較是否爲重複的元素
List 接口的經常使用子類有:
增長元素的方法
刪除元素刪除
替換元素的方法
查詢元素的方法
List<String> list = new ArrayList<String>(); //1,添加元素。 list.add("小紅"); list.add("小梅"); list.add("小強"); //2,插入元素。插入元素前的集合["小紅","小梅","小強"] list.add(1, "老王"); //插入元素後的集合["小紅","老王","小梅","小強"] //3,刪除元素。 list.remove(2);// 刪除元素後的集合["小紅","老王","小強"] //4,修改元素。 list.set(1, "隔壁老王");// 修改元素後的集合["小紅","隔壁老王","小強"] Iterator<String> it = list.iterator(); while (it.hasNext()) { String str = it.next(); System.out.println(str); }
因爲List集合擁有索引,所以List集合迭代方式除了使用迭代器以外,還可使用索引進行迭代
for (int i = 0; i < list.size(); i++) { String str = list.get(i); System.out.println(str); }
在list集合迭代元素中,對元素進行判斷,一旦條件知足就添加一個新元素
public class IteratorDemo { //在list集合迭代元素中,對元素進行判斷,一旦條件知足就添加一個新元素 public static void main(String[] args) { //建立List集合 List<String> list = new ArrayList<String>(); //給集合中添加元素 list.add("abc1"); list.add("abc2"); list.add("abc3"); list.add("abc4"); //迭代集合,當有元素爲"abc2"時,集合加入新元素"aaa" Iterator<String> it = list.iterator(); while(it.hasNext()){ String str = it.next(); //判斷取出的元素是不是"abc2",是就添加一個新元素 if("abc2".equals(str)){ list.add("aaa");// 該操做會致使程序出錯 } } //打印容器中的元素 System.out.println(list); } }
運行上述代碼發生了錯誤 java.util.ConcurrentModificationException這是什麼緣由呢? 在迭代過程當中,使用了集合的方法對元素進行操做。致使迭代器並不知道集合中的變化,容易引起數據的不肯定性
併發修改異常解決辦法:在迭代時,不要使用集合的方法操做元素
那麼想要在迭代時對元素操做咋辦?經過ListIterator迭代器操做元素是能夠的,ListIterator的出現,解決了使用Iterator迭代過程當中可能會發生的錯誤狀況
List接口下有不少個集合,它們存儲元素所採用的結構方式是不一樣的,這樣就致使了這些集合有它們各自的特色,供給咱們在不一樣的環境下進行使用。數據存儲的經常使用結構有:堆棧、隊列、數組、鏈表。咱們分別來了解一下
ArrayList集合數據存儲的結構是數組結構。元素增刪慢,查找快,因爲平常開發中使用最多的功能爲查詢數據、遍歷數據,因此ArrayList是最經常使用的集合
LinkedList集合數據存儲的結構是鏈表結構。方便元素添加、刪除的集合。實際開發中對一個集合元素的添加與刪除常常涉及到首尾操做,而LinkedList提供了大量首尾操做的方法
LinkedList是List的子類,List中的方法LinkedList都是可使用,這裏就不作詳細介紹,咱們只須要了解LinkedList的特有方法便可。在開發時,LinkedList集合也能夠做爲堆棧,隊列的結構使用
LinkedList<String> link = new LinkedList<String>(); //添加元素 link.addFirst("abc1"); link.addFirst("abc2"); link.addFirst("abc3"); //獲取元素 System.out.println(link.getFirst()); System.out.println(link.getLast()); //刪除元素 System.out.println(link.removeFirst()); System.out.println(link.removeLast()); while(!link.isEmpty()){ //判斷集合是否爲空 System.out.println(link.pop()); //彈出集合中的棧頂元素 }
Vector集合數據存儲的結構是數組結構,爲JDK中最先提供的集合。Vector中提供了一個獨特的取出方式,就是枚舉Enumeration,它其實就是早期的迭代器。此接口Enumeration的功能與Iterator接口的功能是相似的。Vector集合已被ArrayList替代。枚舉Enumeration已被迭代器Iterator替代
學習Collection接口時,記得Collection中能夠存放重複元素,也能夠不存放重複元素,那麼咱們知道List中是能夠存放重複元素的。那麼不重複元素給哪裏存放呢?那就是Set接口,它裏面的集合,所存儲的元素就是不重複的
查閱Set集合的API介紹,經過元素的equals方法,來判斷是否爲重複元素
查閱HashSet集合的API介紹:此類實現Set接口,由哈希表支持(其實是一個 HashMap集合)。HashSet集合不能保證的迭代順序與元素存儲順序相同
HashSet集合,採用哈希表結構存儲數據,保證元素惟一性的方式依賴於:hashCode()與equals()方法
什麼是哈希表呢?
哈希表底層使用的也是數組機制,數組中也存放對象,而這些對象往數組中存放時的位置比較特殊,當須要把這些對象給數組中存放時,那麼會根據這些對象的特有數據結合相應的算法,計算出這個對象在數組中的位置,而後把這個對象存放在數組中。而這樣的數組就稱爲哈希數組,即就是哈希表
當向哈希表中存放元素時,須要根據元素的特有數據結合相應的算法,這個算法其實就是Object類中的hashCode方法。因爲任何對象都是Object類的子類,因此任何對象有擁有這個方法。即就是在給哈希表中存放對象時,會調用對象的hashCode方法,算出對象在表中的存放位置,這裏須要注意,若是兩個對象hashCode方法算出結果同樣,這樣現象稱爲哈希衝突,這時會調用對象的equals方法,比較這兩個對象是否是同一個對象,若是equals方法返回的是true,那麼就不會把第二個對象存放在哈希表中,若是返回的是false,就會把這個值存放在哈希表中
總結:保證HashSet集合元素的惟一,其實就是根據對象的hashCode和equals方法來決定的。若是咱們往集合中存放自定義的對象,那麼保證其惟一,就必須複寫hashCode和equals方法創建屬於當前對象的比較方式
給HashSet中存儲JavaAPI中提供的類型元素時,不須要重寫元素的hashCode和equals方法,由於這兩個方法,在JavaAPI的每一個類中已經重寫完畢,如String類、Integer類等
public class HashSetDemo { public static void main(String[] args) { //建立HashSet對象 HashSet<String> hs = new HashSet<String>(); //給集合中添加自定義對象 hs.add("zhangsan"); hs.add("lisi"); hs.add("wangwu"); hs.add("zhangsan"); //取出集合中的每一個元素 Iterator<String> it = hs.iterator(); while(it.hasNext()){ String s = it.next(); System.out.println(s); } } } // 輸出結果以下: wangwu 、lisi 、zhangsan,說明集合中不能存儲重複元素.
給HashSet中存放自定義類型元素時,須要重寫對象中的hashCode和equals方法,創建本身的比較方式,才能保證HashSet集合中的對象惟一
public class Student { private String name; private int age; public Student(String name, int age) { super(); this.name = name; this.age = age; } 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; } @Override public String toString() { return "Student [name=" + name + ", age=" + age + "]"; } @Override public int hashCode() { return name.hashCode()+age; } @Override public boolean equals(Object obj) { if (this == obj){ return true;// 不容許存 } if(!(obj instanceof Student)){ System.out.println("類型錯誤"); return false; } Student other = (Student) obj; return this.age == other.age && this.name.equals(other.name); } }
public class HashSetDemo { public static void main(String[] args) { //建立HashSet對象 HashSet hs = new HashSet(); //給集合中添加自定義對象 hs.add(new Student("zhangsan",21)); hs.add(new Student("lisi",22)); hs.add(new Student("wangwu",23)); hs.add(new Student("zhangsan",21)); //取出集合中的每一個元素 Iterator it = hs.iterator(); while(it.hasNext()){ Student s = (Student)it.next(); System.out.println(s); } } } // 輸出結果以下: Student[name=list , age = 21] Student[name=zhangsan , age = 21] Student[name=wangwu ,age = 23] // 說明集合中不能存儲重複的元素
咱們知道HashSet保證元素惟一,但是元素存放進去是沒有順序的,那麼咱們要保證有序,怎麼辦呢
在HashSet下面有一個子類LinkedHashSet,它是鏈表和哈希表組合的一個數據存儲結構
public class LinkedHashSetDemo { public static void main(String[] args) { Set<String> set = new LinkedHashSet<String>(); set.add("bbb"); set.add("aaa"); set.add("abc"); set.add("bbc"); Iterator it = set.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } }
TreeSet 是一個有序的集合,它的做用是提供有序的Set集合
1.建立Person類實現Person implements Comparable<Person>
public class Person implements Comparable<Person> { private String name; private int age; 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 Person(String name, int age) { this.name = name; this.age = age; } public Person() { } @Override public int compareTo(Person o) { /* return -1; //-1表示放在紅黑樹的左邊,即逆序輸出 return 1; //1表示放在紅黑樹的右邊,即順序輸出 return 0; //表示元素相同,僅存放第一個元素 主要條件 姓名的長度,若是姓名長度小的就放在左子樹,不然放在右子樹 */ int i = this.name.length() - o.name.length(); //姓名的長度相同,不表明內容相同,若是按字典順序此 String 對象位於參數字符串以前,則比較結果爲一個負整數。 //若是按字典順序此 String 對象位於參數字符串以後,則比較結果爲一個正整數。 //若是這兩個字符串相等,則結果爲 0 int i2 = i == 0 ?this.name.compareTo(o.name) :i; //姓名的長度和內容相同,不表明年齡相同,因此還要判斷年齡 int i3 = i2 == 0 ? this.age - o.age: i2; return i3; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
建立測試類
public static void main(String[] args) { Set<Person> s = new TreeSet<Person>(); s.add(new Person("a", 1)); s.add(new Person("c", 3)); s.add(new Person("b", 2)); System.out.println(s); }
建立Person不須要實現Comparable接口
public class Person { private String name; private int age; 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 Person(String name, int age) { this.name = name; this.age = age; } public Person() { } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
自定義比較器MyComparator implements Comparator<Person>
public class MyComparator implements Comparator<Person>{ @Override public int compare(Person o1, Person o2) { int i = o1.getName().length() - o2.getName().length(); //姓名的長度相同,不表明內容相同,若是按字典順序此 String 對象位於參數字符串以前,則比較結果爲一個負整數。 //若是按字典順序此 String 對象位於參數字符串以後,則比較結果爲一個正整數。 //若是這兩個字符串相等,則結果爲 0 int i2 = i == 0 ? o1.getName().compareTo(o2.getName()):i; //姓名的長度和內容相同,不表明年齡相同,因此還要判斷年齡 int i3 = i2 == 0 ? o1.getAge() - o2.getAge():i2; return i3; } }
自定義測試類
public class Tests { public static void main(String[] args) { Set<Person> s = new TreeSet<Person>(new MyComparator()); s.add(new Person("a", 1)); s.add(new Person("c", 3)); s.add(new Person("b", 2)); System.out.println(s); } }