集合能夠看做是一種容器,用來存儲對象信息。全部集合類都位於java.util包下,但支持多線程的集合類位於java.util.concurrent包下。java
數組與集合的區別node
Collection 接口數組
序號 | 接口描述 |
---|---|
1 | Collection 接口 Collection 是最基本的集合接口。一個 Collection 表明一組 Object ,即 Collection 元素 Java不提供直接繼承Collection的類,只提供繼承於它的子接口(如List,Set) Collection接口存儲一組不惟一,無序的對象 |
2 | List 接口 List 是一個有序的 Collection,此接口可以精準的控制每一個元素插入的位置,能夠經過索引來訪問 List 中的元素 第一個元素索引爲0,並且容許有相同的元素 List 接口存儲一組不惟一,有序(插入順序)的對象 |
3 | Set 接口 Set 具備與 Collection 徹底同樣的接口,只是行爲上不一樣,Set 不保存重複的元素 |
4 | SortedSet 接口 繼承於 Set 的子接口,可是它保存的是惟一有序的集合 |
5 | Queue 接口 Queue 就是隊列,隊列的特色是先進先出,一般,不容許隨機訪問元素。 |
Set 與 List 的區別安全
Collection 實現類(經常使用集合類)數據結構
序號 | 類描述 |
---|---|
1 | List |➡ArrayList 該類實現了可變大小的數組,爲隨機訪問和遍歷元素提供了更好的性能 線程不安全的(異步),多線程狀況下不要使用。 ArrayList 擴容長度 50%,插入刪除效率低。 底層爲數組結構 |
2 | List |➡Vector 該類與ArrayList 類很是類似 線程安全的(同步),多線程狀況下,該類容許默認擴容長度100% 底層爲數組結構 |
3 | List/Queue |➡LinkedList 該類沒有同步方法,若是多線程同時訪問要給List,則必須本身實現訪問同步 解決方法就是建立List時創造一個同步的List = Collections.synchronizedList(newLinkedList(...)); 底層爲雙向鏈表結構 |
4 | Queue |➡ArrayQueue 該類是一個循環隊列,繼承了AbstractList 抽象類 底層爲數組結構 |
5 | Set |➡HashSet 該類不容許出現重複元素,不保證集合中元素的順序,容許包含值爲Null的元素,但最多一個 底層爲哈希表結構(一個HashMap實例)由數組+鏈表/紅黑樹構成(鏈表長度大於8切換爲紅黑樹) |
6 | Set |➡TreeSet 該類實現排序等功能 底層爲紅黑樹結構 |
7 | Set |➡HashSet |➡LinkedHashSet 該類不只保證了元素的惟一,同時元素存放是由順序的 底層爲鏈表+哈希表結構 |
特別說明多線程
JDK 1.8以前,哈希表是由 數組+鏈表 實現,即便用鏈表處理衝突,同一hash值的鏈表都存儲在一個鏈表裏。可是當位於一個桶中的元素較多,即hash值相等的元素較多時,經過key值依次查找的效率較低。框架
而 JDK 1.8,哈希表存儲採用數組+鏈表+紅黑樹實現,當鏈表長度超過閾值(8)時,將鏈表轉換爲紅黑樹,這樣大大減小了查找時間。異步
代碼表現ide
public class LinkedListDemo{ public static void main(String[] args) { LinkedList<String> link = new LinkedList<String>(); //添加元素 link.addFirst("abc1"); link.addFirst("abc2"); link.addFirst("abc3"); System.out.println(link); // 獲取元素 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()); //彈出集合中的棧頂元素(彈棧) } System.out.println(link); } } /* 輸出結果: [abc3, abc2, abc1] abc3 abc1 abc3 abc1 abc2 [] */
public class HashSetDemo { public static void main(String[] args) { //建立 Set集合 HashSet<String> set = new HashSet<String>(); //添加元素 set.add(new String("cba")); set.add("abc"); set.add("bac"); set.add("cba"); //遍歷 for (String name : set) { System.out.println(name); } System.out.println("==========") //建立集合對象 該集合中存儲 Student類型對象 HashSet<Student> stuSet = new HashSet<Student>(); //存儲 Student stu = new Student("于謙", 43); stuSet.add(stu); stuSet.add(new Student("郭德綱", 44)); stuSet.add(new Student("于謙", 43)); stuSet.add(new Student("郭麒麟", 23)); stuSet.add(stu); for (Student stu2 : stuSet) { System.out.println(stu2); } } } /* 輸出結果: cba abc bac ========== Student [name=郭德綱, age=44] Student [name=于謙, age=43] Student [name=郭麒麟, age=23] tips: 根據結果咱們發現字符串「cba」與Student [name=于謙, age=43]只存儲了一個,也就是說重複的元素set集合不存儲 */
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<String> it = set.iterator(); while (it.hasNext()) { System.out.println(it.next()); } } } /* 運行結果 bbb aaa abc bbc */
java.utils.Collections 是集合工具類,用來對集合進行操做工具
public class CollectionsDemo { public static void main(String[] args) { ArrayList<Integer> list = new ArrayList<Integer>(); //原來寫法 //list.add(12); //list.add(14); //list.add(15); //list.add(1000); //採用工具類 完成 往集合中添加元素 Collections.addAll(list, 5, 222, 1,2); System.out.println(list); //排序方法 Collections.sort(list); System.out.println(list); } } /* 運行結果: [5, 222, 1, 2] [1, 2, 5, 222] */
Comparator比較器
public class CollectionsDemo3 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); list.add("cba"); list.add("aba"); list.add("sba"); list.add("nba"); //排序方法 按照第一個單詞的降序 Collections.sort(list, new Comparator<String>() { @Override public int compare(String o1, String o2) { /* 兩個對象比較的結果有三種:大於,等於,小於。 若是要按照升序排序,則 o1 小於 o2 若是要按照降序排序,則 o1 小於 o2 */ return o2.charAt(0) - o1.charAt(0); } }); System.out.println(list); } } public int compare(String o1, String o2)
//實體 public class Student{ private String name; private int age; public Student() { } public Student(String name, int age) { 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 + '}'; } } //測試類 public class Demo { public static void main(String[] args) { // 建立四個學生對象 存儲到集合中 ArrayList<Student> list = new ArrayList<Student>(); list.add(new Student("rose",18)); list.add(new Student("jack",16)); list.add(new Student("abc",16)); list.add(new Student("ace",17)); list.add(new Student("mark",16)); /* 讓學生 按照年齡排序 升序 */ // Collections.sort(list);//要求 該list中元素類型 必須實現比較器Comparable接口 for (Student student : list) { System.out.println(student); } } } /* 發現 當咱們調用Collections.sort()方法的時候程序報錯 緣由 若是想要集合中的元素完成排序,那麼必需要實現比較器Comparable接口、 */ public class Student implements Comparable<Student>{ .... @Override public int compareTo(Student o) { return this.age-o.age;//升序 } } /* 運行結果 Student{name='jack', age=16} Student{name='abc', age=16} Student{name='mark', age=16} Student{name='ace', age=17} Student{name='rose', age=18} */
Collections.sort(list, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { return o2.getAge()-o1.getAge();//以學生的年齡降序 } }); /* 上列代碼,效果與上邊輸出同樣 下列代碼,爲多規則斷定 */ Collections.sort(list, new Comparator<Student>() { @Override public int compare(Student o1, Student o2) { // 年齡降序 int result = o2.getAge()-o1.getAge(); //年齡降序 if(result==0){//第一個規則判斷完了 下一個規則 姓名的首字母 升序 result = o1.getName().charAt(0)-o2.getName().charAt(0); } return result; } });
Map接口,存儲一組鍵值對對象,提供key/value的映射
序號 | 描述類 |
---|---|
1 | Map |➡HashMap 該類是一個散列表,它存儲的內容是鍵值對(key/value)映射 根據鍵的HashCode值存儲數據,具備很快的訪問速度,最多記錄一條爲Null的鍵,不支持線程同步 底層爲哈希表結構(數組+鏈表/紅黑樹) |
2 | Map |➡HashMap |➡LinkedHashMap 底層爲 鏈表 + 哈希表 |
經常使用方法
public class MapDemo { public static void main(String[] args) { //建立 map對象 HashMap<String, String> map = new HashMap<String, String>(); //添加元素到集合 map.put("黃曉明", "楊穎"); map.put("文章", "馬伊琍"); map.put("鄧超", "孫儷"); System.out.println(map); //String remove(String key) System.out.println(map.remove("鄧超")); System.out.println(map); // 想要查看 黃曉明的媳婦 是誰 System.out.println(map.get("黃曉明")); System.out.println(map.get("鄧超")); } } /* tips: 使用put方法時,若指定的鍵(key)在集合中沒有,則沒有這個鍵對應的值,返回null,並把指定的鍵值添加到集合中 若指定的鍵(key)在集合中存在,則返回值爲集合中鍵對應的值(該值爲替換前的值),並把指定鍵所對應的值,替換成指定的新值 */
Map遍歷鍵找值
public class MapDemo01 { /* 1.獲取Map中全部的鍵,因爲鍵是惟一的,因此返回一個Set集合存儲全部的鍵。方法提示: keyset() 2.遍歷鍵的Set集合,獲得每個鍵。 3.根據鍵,獲取鍵所對應的值。方法提示: get(K key) */ public static void main(String[] args) { //建立Map集合對象 HashMap<String, String> map = new HashMap<String,String>(); //添加元素到集合 map.put("胡歌", "霍建華"); map.put("郭德綱", "于謙"); map.put("薛之謙", "大張偉"); //獲取全部的鍵 獲取鍵集 Set<String> keys = map.keySet(); // 遍歷鍵集 獲得 每個鍵 for (String key : keys) { //key 就是鍵 //獲取對應值 String value = map.get(key); System.out.println(key+"的CP是:"+value); } } }
Entry鍵值對對象以及遍歷
/* Map中存放的是兩種對象 key(鍵)/value(值),它們在在Map中是一一對應關係。一組K/V又稱作Map中的一個Entry(項),Entry將鍵值對的對應關係封裝成了對象,即鍵值對對象。這樣咱們在遍歷Map集合時,就能夠從每個鍵值對(Entry)對象中獲取對應的鍵與對應的值。 方法: public K getKey() :獲取Entry對象中的鍵。 public V getValue() :獲取Entry對象中的值。 操做步驟: 1. 獲取Map集合中,全部的鍵值對(Entry)對象,以Set集合形式返回。方法提示: map.entrySet() 。 2. 遍歷包含鍵值對(Entry)對象的Set集合,獲得每個鍵值對(Entry)對象。 */ public class MapDemo02 { public static void main(String[] args) { // 建立Map集合對象 HashMap<String, String> map = new HashMap<String,String>(); // 添加元素到集合 map.put("胡歌", "霍建華"); map.put("郭德綱", "于謙"); map.put("薛之謙", "大張偉"); // 獲取 全部的 entry對象 entrySet Set<Entry<String,String>> entrySet = map.entrySet(); // 遍歷獲得每個entry對象 for (Entry<String, String> entry : entrySet) { // 解析 String key = entry.getKey(); String value = entry.getValue(); System.out.println(key+"的CP是:"+value); } } } /* tips:Map集合不能直接使用迭代器或者foreach進行遍歷。可是轉成Set以後就可使用了。 */
HashMap存儲自定義類型鍵值,使用map.keySet()方法
/* 每位學生(姓名,年齡)都有本身的家庭住址。則將學生對象和家庭住址存儲到 map集合中。學生做爲鍵, 家庭住址做爲值 */ public class Student { private String name; private int age; public Student() { } public Student(String name, int age) { 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; } public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Student student = (Student) o; return age == student.age && Objects.equals(name, student.name); } @Override public int hashCode() { return Objects.hash(name, age); } } /*map.keySet()方法*/ public class HashMapTest { public static void main(String[] args) { //1,建立Hashmap集合對象。 Map<Student,String>map = new HashMap<Student,String>(); //2,添加元素。 map.put(newStudent("lisi",28), "上海"); map.put(newStudent("wangwu",22), "北京"); map.put(newStudent("zhaoliu",24), "成都"); map.put(newStudent("zhouqi",25), "廣州"); map.put(newStudent("wangwu",22), "南京"); //3,取出元素。鍵找值方式 Set<Student> keySet = map.keySet(); for(Student key: keySet){ Stringvalue = map.get(key); System.out.println(key.toString()+"....."+value); } } }
Java 9 ,添加了幾重集合工廠方法,更方便建立少許元素的集合
public class HelloJDK9 { public static void main(String[] args) { Set<String> str1=Set.of("a","b","c"); //str1.add("c");這裏編譯的時候不會錯,可是執行的時候會報錯,由於是不可變的集合 System.out.println(str1); Map<String,Integer> str2=Map.of("a",1,"b",2); System.out.println(str2); List<String> str3=List.of("a","b"); System.out.println(str3); } } /* 兩點注意: 1.of()方法只是Map,List,Set這三個接口的靜態方法,其父類接口和子類實現並無這類方法,好比 HashSet,ArrayList等待; 2.返回的集合是不可變的; */
數據存儲的經常使用結構有:棧、隊列、數組、鏈表和紅黑樹。咱們分別來了解一下:
棧(stack) ,又稱堆棧,它是運算受限的線性表,其限制是僅容許在標的一端進行插入和刪除操做,不容許在其餘任何位置進行添加、查找、刪除等操做。
簡單的說,採用該結構的集合,對元素的存取有以下的特色
這裏兩個名詞須要注意
數組(Array),是有序的元素序列,數組是在內存中開闢一段連續的空間,並在此空間存放元素。就像是一排出租屋,有100個房間,從001到100每一個房間都有固定編號,經過編號就能夠快速找到租房子的人。
簡單的說,採用該結構的集合,對元素的存取有以下的特色
鏈表(linked list),由一系列結點node組成(鏈表中每個元素稱爲結點),結點能夠在運行時動態生成。每一個結點包括兩個部分:一個是存儲數據元素的數據域,另外一個是存儲下一個結點地址的指針域。咱們常說的鏈表結構有單向鏈表與雙向鏈表,那麼這裏給你們介紹的是單向鏈表。
簡單的說,採用該結構的集合,對元素的存取有以下的特色
二叉樹(binary tree) 是每一個結點不超過2的有序樹(tree)。簡單的理解,就是一種相似於咱們生活中樹的結構,只不過每一個結點上都最多隻能有兩個子結點。二叉樹是每一個節點最多有兩個子樹的樹結構。頂上的叫根結點,兩邊被稱做"左子樹"和"右子樹"
咱們要說的是二叉樹的一種比較有意思的叫作紅黑樹,紅黑樹自己就是一顆二叉查找樹,將節點插入後,該樹仍然是一顆二叉查找樹。也就意味着,樹的鍵值仍然是有序的。
紅黑樹的約束
紅黑樹的特色,速度特別快,趨近平衡樹,查找葉子元素最少和最屢次數很少於二倍