Java 集合看這一篇夠了

主要集合概述

Java 主要有 3 種重要的集合類型:

  • List:是一個有序集合,可以放置重複的元素

  • Set:是一個無序集合,不允許放置重複的元素

  • Map:是一個無序集合,集合中包含一個對象,一個對象,鍵對象不允許重複,值對象可以重複

    • 就像身份證號和姓名 : <鍵 , 值>

集合中只能存儲引用類型,不能存儲基本數據類型

集合中 Collection 的繼承結構圖(重要·背下來)

集合中 Collection 的繼承結構圖

Collection 中的常用方法

	boolean	add(E e)
	boolean	addAll(Collection<? extends E> c)
	void	clear()
	boolean	contains(Object o)
	boolean	containsAll(Collection<?> c)
	int	hashCode()
	boolean	isEmpty()
	Iterator<E>	iterator()
	boolean	remove(Object o)
	boolean	removeAll(Collection<?> c)
	int	size()
	Object[] toArray()
  • 舉例1

    import java.util.*;
    
    public class Test02 {
    	public static void main(String[] args) {
    		// 創建集合
    		Collection c = new ArrayList();
    		// 添加元素
    		c.add(1);// auto boxing
    		c.add(new Integer(1));
    		Object o = new Object();
    		c.add(o); // 集合中只能單個存儲元素,並且只能存儲引用類行
    		c.add(new Customer("張三", 23));
    		// 獲取元素個數
    		System.out.println(c.size());// 4
    		
    		// 判斷集合是否爲空
    		System.out.println(c.isEmpty());// false
    		Object[] resO = c.toArray();
    		for (int i = 0; i < resO.length; i++) {
    			System.out.println(resO[i]);
    		}
    		// 移除某一個引用
    		c.remove(1);
    		System.out.println(c.size());//3
    		// 清空集合
    		c.clear();
    		System.out.println(c.size());//0
    		
    		// 判斷集合是否爲空
    		System.out.println(c.isEmpty());// true
    	}
    }
    
    class Customer{
    	String name;
    	int age;
        
    	public Customer(String name, int age) {
    		this.name = name;
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "Customer [name=" + name + ", age=" + age + "]";
    	}
    }
    
    
  • 舉例2- Iterator 迭代器

    Iterator iterator(); 獲取集合所依賴的迭代器對象, 通過迭代器中的方法完成集合的遍歷/迭代
    注意: 這種方法是所有集合通用的遍歷方式

    import java.util.*;
    /*
     Iterator iterator(); 獲取集合所依賴的迭代器對象
     通過迭代器中的方法完成集合的遍歷/迭代
     注意: 這種方法是所有集合通用的遍歷方式
     */
    public class Test03 {
    	public static void main(String[] args) {
    		// 創建集合對象
    		Collection c = new LinkedList();
    		// 添加元素
    		c.add(122); // 自動裝箱
    		c.add(false);// 自動裝箱
    		c.add(399);// 自動裝箱
    		
    		// 迭代遍歷
    		// 獲取迭代器對象
    		// 不需要關心底層集合的具體類型,所有集合依賴的迭代器都實現了 java.util.Iterator; 接口
    		Iterator iterator = c.iterator(); // 迭代器對象是面向接口編程
    		// iterator 是引用,保存了內存地址,指向堆中的“迭代器對象”
    		System.out.println(iterator); // java.util.LinkedList$ListItr@15db9742
    		
    		// 開始調用方法,完成遍歷,迭代 
    		// 原則, 調用 iterator.next() 方法之前必須調用 iterator.hasNext()
    		// while循環
    		while(iterator.hasNext()) {
    			System.out.println(iterator.next());
    		}
    		// for 循環
    		for(Iterator it = c.iterator(); it.hasNext();) {
    			System.out.println(it.next());
    		}
    	}
    }
    
    
  • 舉例3-contains()方法

    contains()底層是調用的equals()方法

    注意:自己創建的類一般都要重寫 Object 類中的 equals() 方法,使之用於比較內容

    import java.util.*;
    //  boolean contains(Object o)
    public class Test04 {
    	public static void main(String[] args) {
    		// 創建集合
    		Collection c = new ArrayList();
    		// 創建 Integer 類型的對象
    		Integer i1 = new Integer(256);
    		// 添加元素
    		c.add(i1);
    		System.out.println(c.contains(256));// true
    		// 創建 Integer 類型的對象
    		Integer i2 = new Integer(256);
    		// 雖然i2沒有添加進c集合裏面,但是contains()底層是調用的equals()方法
    		// Integer重寫了Object類中的equals方法
    		// 所以下面執行結果爲true
    		System.out.println(c.contains(i2));// true
    		
    		Manger m1 = new Manger("張三", 12);
    		c.add(m1);
    		System.out.println(c.contains(m1));// true
    		Manger m2 = new Manger("張三", 12);
    		// Manger類重寫equals方法後
    		System.out.println(c.contains(m2));// true
    	}
    }
    
    class Manger{
    	String name;
    	int id;
    	public Manger(String name, int id) {
    		this.name = name;
    		this.id = id;
    	}
    	@Override
    	public boolean equals(Object obj) {
    		if(this == obj) {
    			return true;
    		}
    		if(obj instanceof Manger) {
    			Manger m = (Manger)obj;
    			return this.name == m.name && this.id == m.id;
    		}
    		return false;
    	}
    	
    }
    
    • ArrayList 中的contains()方法的實現

      public boolean contains(Object o) {
          return indexOf(o) >= 0;
      }
      
      public int indexOf(Object o) {
          if (o == null) {
              for (int i = 0; i < size; i++)
                  if (elementData[i]==null)
                      return i;
          } else {
              for (int i = 0; i < size; i++)
                  if (o.equals(elementData[i]))
                      return i;
          }
          return -1;
      }
      
  • 舉例4-集合中的remove()方法

    remove() 方法和contains()方法都需要集合中的對象重寫 equals() 方法。 因爲Object類中的equals方法是比較內存地址,而在現實的業務邏輯中不能比較內存地址,該比較內容。

    import java.util.*;
    
    public class Test05 {
    	public static void main(String[] args) {
    		// 創建集合
    		Collection c = new ArrayList();
    		// 添加元素
    		Integer i1 = new Integer(10);
    		c.add(i1);
    		Integer i2 = new Integer(10);
    		System.out.println(c.remove(i2));// true
    		System.out.println(c.size());// 0
    		
    		Manger m1 = new Manger("張三", 12);
    		c.add(m1);
    		Manger m2 = new Manger("張三", 12);
    		// Manger類重寫equals方法後
    		System.out.println(c.remove(m2));// true	
    		System.out.println(c.size());//0
    	}
    }
    
    
  • 舉例5-迭代器中的remove()方法

    在使用迭代器循環刪除集合中的元素的時候,不能使用集合的remove()方法,只能使用迭代器的remove()方法

    import java.util.*;
    
    public class Test06 {
    	public static void main(String[] args) {
    		// 創建集合
    		Collection c = new ArrayList();
    		
    		c.add(1);
    		c.add(2);
    		c.add(3);
    		// 創建迭代器對象
    		Iterator it = c.iterator();
    		while(it.hasNext()) {
    			Object o = it.next();
    			it.remove();// 使用迭代器刪除
    		}
    		System.out.println(c.size());// 0
    		// 如果在迭代的過程中不使用迭代器的 remove()方法 
    		// 使用 集合的 remove()方法可以嗎
    			// 當然不可以,在第一次循環的時候沒問題,但是第二次循環的時候 it對應的集合已經不是原來的集合了
    			// 報錯ConcurrentModificationException
    		/*
    		 	c.add(1);
    			c.add(2);
    			c.add(3);
    			it = c.iterator();// 需要重新指定 it
    			while(it.hasNext()) {
    				Object o = it.next();
    				c.remove(o);// 使用結合中的方法刪除 // 報錯ConcurrentModificationException
    			}
    			System.out.println(c.size()); // 0
    		 */
    	}
    }
    

    List集合詳解

    List 是一個接口, 裏面有自己規定的(獨特的)方法

    public interface List<E> extends Collection<E>

    • 舉例1-List集合中存儲的元素有序可以重複

      import java.util.*;
      
      public class Test07 {
      	public static void main(String[] args) {
      		List list = new ArrayList();
      		list.add(2);
      		list.add(4);
      		list.add(3);
      		list.add(34);
      		// 遍歷
      		Iterator it = list.iterator();
      		while(it.hasNext()) {
      			System.out.println(it.next());
      		}
      		// E get(int index) 獲取對應下標的元素
      		System.out.println(list.get(3));
      	}
      }
      
    • 舉例2-深入List集合

      • ArrayList集合底層是數組,數組是有下標的,所以ArrayList有很多自己的特性(關於下標的特性)

      • ArrayList集合底層默認初始化數組大小爲 10 ,擴大之後的容量是原容量的 1.5 倍

      • Vector 集合底層默認初始化數組大小爲10,擴大之後的容量是原容量的 2 倍

        如何優化 ArrayLIst 和 Vector?

        ​ 儘量減少擴容操作,因爲擴容需要數組拷貝。一般推薦在創建集合的時候指定初始化數組的大小

      • 方法

        void add(int index, E element);
        Object get(int index);
        Object remove(int index);
        Object set(int index, Object element);
        List subList(int fromIndex, int toIndex)
        
      import java.util.*;
      
      public class Test08 {
      	public static void main(String[] args) {
      		List l = new ArrayList();
      		l.add(23);
      		l.add(123);
      		l.add(321);
      		l.add(69);
      		// 在下標爲 1 的地方添加 555
      		l.add(1, 555);
      		// 將下標2的地方的數據更改爲 100
      		l.set(2, 100);
      		// 獲取第1個元素
      		System.out.println(l.get(0));
      		System.out.println("=======");
      		// 遍歷(List 集合中特有的遍歷方式)
      		for(int i=0; i<l.size(); i++) {
      			Object o = l.get(i);
      			System.out.println(o);
      		}
      	}
      }
      

Set對應的類及常用方法

Set 中存儲的元素是無序不可重複的,存進去的順序和取出來的順序不一定一致。

HashSet 類實現了Set接口(HashSet 的底層時間上是一個 HashMap,見下圖·java的HashSet源碼)

HashMap底層是哈希表

SortedSet 接口繼承了Set 接口,其存儲的元素也是無需,不可重複的,但是存進去的元素可以按照元素的大小自動排序,TreeSet 類實現了 SortedSet 接口

hashSet的實現源碼

  • 哈希表/散列表(較高的查找/刪除/增加效率

    • 哈希表是數組和單向鏈表的結合

      hash表是數組和單向鏈表的結合

    • 哈希表的本質是一個數組,只不過這個數組中的每一個元素都是一個單向鏈表

      hash表是數組和單向鏈表的結合

    • 數組中每一個元素存儲的是一個單向鏈表,單向鏈表中每一個節點存儲的是:final int hash, Object key, Object value, Node<> next

      • hash 值是通過 key調用hashcode()方法得到的值,再通過hash算法得到的值

        如何通過key得到對應的hash值

      • 在數組中每一個單向鏈表中節點的hash值都是相同的,代表了數組的下標

      • hashMap中有一個方法用於查找對應的節點:Object get(Object key)

        public V get(Object key) {
                Node<K,V> e;
                return (e = getNode(hash(key), key)) == null ? null : e.value;
        }
        
      • hashMap中有一個添加元素的方法:void put(Object key, Object value)

        public V put(K key, V value) {
                return putVal(hash(key), key, value, false, true);
        }
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                           boolean evict) {
                Node<K,V>[] tab; Node<K,V> p; int n, i;
            	// tab = table
                if ((tab = table) == null || (n = tab.length) == 0)
                    n = (tab = resize()).length;
            	// hash 和 數組下標的對應關係:i = (n - 1) & hash
                if ((p = tab[i = (n - 1) & hash]) == null)
                    tab[i] = newNode(hash, key, value, null);// 新的單向鏈表
                else {// 已經存在的單向鏈表
                    Node<K,V> e; K k;
                    if (p.hash == hash &&
                        ((k = p.key) == key || (key != null && key.equals(k))))
                        e = p;
                    else if (p instanceof TreeNode)
                        e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                    else {
                        for (int binCount = 0; ; ++binCount) {
                            if ((e = p.next) == null) {
                                p.next = newNode(hash, key, value, null);
                                if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                    treeifyBin(tab, hash);
                                break;
                            }
                            if (e.hash == hash &&
                                ((k = e.key) == key || (key != null && key.equals(k))))
                                break;
                            p = e;
                        }
                    }
                    if (e != null) { // existing mapping for key
                        V oldValue = e.value;
                        if (!onlyIfAbsent || oldValue == null)
                            e.value = value;
                        afterNodeAccess(e);
                        return oldValue;
                    }
                }
                ++modCount;
                if (++size > threshold)
                    resize();
                afterNodeInsertion(evict);
                return null;
            }
        
        

散列表的數據結構

HashSet集合詳解
  • HashSet實際上是一個HashMap,HashMap底層採用了哈希表數據結構
    • HashMap的初始容量是 16,縮放因子是 0.75
  • 哈希表又叫散列表。哈希表的底層是一個數組,這個數組的每一個元素是一個單向鏈表,每一個單向鏈表都有一個獨一無二的hash值,代表了數組的下標
    • 在一個單向鏈表中每一個節點的hash值是相同的。
      • hash值實際上是 key 調用 hashCode 方法,再通過 hash function 得到的值。
  • 向hash 表中添加元素的過程:
    • 先調用被存儲的 keyhashCode方法,經過 hash function 得到 hash
      • 如果在這個hash表中不存在這個 hash 值,則直接加入元素。
      • 如果該 hash 值已經存在,繼續調用key之間的 equals 方法
        • 如果equals方法返回 false,則將該元素田間
        • 如果equals方法返回 true,則放棄添加該元素(元素不可重複,所以就不添加了)
import java.util.*;

public class Test09 {
	public static void main(String[] args) {
		Set s = new HashSet();
		s.add(1);
		s.add(1);
		s.add(188);
		s.add(100);
		s.add(74);
		s.add(85);
		
		// 遍歷
		// 創建迭代器
		Iterator it = s.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
// 輸出
1
100
85
74
188
  • 關於往Set集合裏面添加元素

    • 存儲在hashSet或者HashMap集合中Key部分的的元素,需要同時重寫 hashCode()equals()方法
    import java.util.*;
    public class Test10 {
    		
    	public static void main(String[] args) {
    		Set s = new HashSet();
    		Employee e1 = new Employee("1000", "jack");
    		Employee e2 = new Employee("1000", "jack");
    		Employee e3 = new Employee("2000", "cook");
    		Employee e4 = new Employee("2000", "book");
    		Employee e5 = new Employee("4003", "barabase");
    		// 添加元素的時候,會先調用Employee裏面的hashCode方法得到hash值,hash不一樣往數組裏面添加
    		// hash 一樣,調用equals方法,返回false,插入到對應hash單向鏈表中
    		// 返回 true,不添加,所以要重寫對應類裏面的hashCode()方法和
    		s.add(e1);
    		s.add(e2);
    		s.add(e3);
    		s.add(e4);
    		s.add(e5);
    		
    		System.out.println(s.size());
    	}
    }
    
    class Employee{
    	String no;
    	String name;
    	public Employee(String no, String name) {
    		this.no = no;
    		this.name = name;
    	}
    	// 重寫 Object 中的 hashCode
    	@Override
    	public int hashCode() {
    		return this.no.hashCode();//直接使用 String 類裏面的hashCode方法
    	}
    	// 重寫 Object中的equals方法
    	@Override
    	public boolean equals(Object obj) {
    		if(this == obj) {
    			return true;
    		}
    		if(obj instanceof Employee) {
    			Employee e = (Employee)obj;
    			return (this.no == e.no && this.name == e.name);
    		}
    		return false;
    	}
    }
    
SortedSet接口介紹
  • SortedSet是一個接口

    java.util.Set;
        java.util.SortedSet;//無需不可重複,但是可以按照元素大小自動排序 
        	java.util.TreeSet;
    
    import java.text.ParseException;
    import java.text.SimpleDateFormat;
    import java.util.*;
    
    public class Test11 {
    	public static void main(String[] args) throws ParseException {
    		SortedSet ss = new TreeSet();
    		ss.add(10);
    		ss.add(22);
    		ss.add(12);
    		ss.add(34);
    		ss.add(28);
    		// 遍歷
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    /* 輸出
    10
    12
    22
    28
    34
    */
    		// 字符串
    		SortedSet strs = new TreeSet();
    		String s1 = "Jack";
    		String s2 = "Tom";
    		String s3 = "Jerry";
    		String s4 = "Pack";
    		strs.add(s1);
    		strs.add(s2);
    		strs.add(s3);
    		strs.add(s4);
    		it = strs.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    /* 輸出
    Jack
    Jerry
    Pack
    Tom
    */		
    		// 日期
    		String st1 = "2008-08-08";
    		String st2 = "2009-08-08";
    		String st3 = "2008-02-03";
    		String st4 = "2008-12-14";
    		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
    		Date d1 = sdf.parse(st1);
    		Date d2 = sdf.parse(st2);
    		Date d3 = sdf.parse(st3);
    		Date d4 = sdf.parse(st4);
    		SortedSet times = new TreeSet();
    		times.add(d1);
    		times.add(d2);
    		times.add(d3);
    		times.add(d4);
    		// 遍歷
    		it = times.iterator();
    		while(it.hasNext()) {
    			Object o = it.next();
    			if(o instanceof Date) {
    				Date t = (Date) o;
    				System.out.println(sdf.format(t));
    			}
    		}
    /* 輸出
    2008-02-03
    2008-08-08
    2008-12-14
    2009-08-08
    */	
    	}
    }
    
    
    • Collection 裏面只能存儲引用類型

    • SortedSet裏面存儲的元素不重複,無需,但是會自動根據元素大小來排序

      • 爲什麼不同類型的數據(Integer, String, Date)都可以進行比較大小呢?

        因爲他們都實現了 Compareable接口,實現了裏面的 compareTo() 方法

  • SortedSet集合裏面的元素是如何排序的?

    在上面的程序中,我們使用了Sun公司已經寫好的Date類/String類型的數據存儲到TreeSet集合中,發現可以直接排序,那麼我們嘗試以下往SortedSet中存儲我們自己寫的類會發生什麼呢?

    import java.util.*;
    public class Test12 {
    	public static void main(String[] args) {
    		SortedSet ss = new TreeSet();
    		User u1 = new User(10);
    		User u2 = new User(13);
    		User u3 = new User(12);
    		User u4 = new User(15);
    		User u5 = new User(11);
    		ss.add(u1);
    		ss.add(u2);
    		ss.add(u3);
    		ss.add(u4);
    		ss.add(u5);
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    	}
    }
    class User{
    	int age;
    	public User(int age) {
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "User[age="+this.age+"]";
    	}
    	
    }
    
    
    // 編譯成功,運行錯誤
    Exception in thread "main" java.lang.ClassCastException: com.test.collections.User cannot be cast to java.lang.Comparable
    	at java.util.TreeMap.compare(Unknown Source)
    	at java.util.TreeMap.put(Unknown Source)
    	at java.util.TreeSet.add(Unknown Source)
    	at com.test.collections.Test12.main(Test12.java:11)
    
    

    運行報 “類型轉換錯誤” 的錯誤, 我們自己寫的類不能轉換成 java.lang.Comparable 類型,所以我們應該實現Comparable接口裏面的方法

    所以說 凡是放在 SortedSet 裏面的元素 必須 實現了Comparable接口裏面的 compareTo() 方法

    import java.util.*;
    public class Test12 {
    	public static void main(String[] args) {
    		SortedSet ss = new TreeSet();
    		User u1 = new User(10);
    		User u2 = new User(13);
    		User u3 = new User(12);
    		User u4 = new User(15);
    		User u5 = new User(11);
    		ss.add(u1);
    		ss.add(u2);
    		ss.add(u3);
    		ss.add(u4);
    		ss.add(u5);
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    	}
    }
    class User implements Comparable{// 繼承Comparable接口實現裏面的方法
    	int age;
    	public User(int age) {
    		this.age = age;
    	}
    	@Override
    	public String toString() {
    		return "User[age="+this.age+"]";
    	}
    	// 實現Comparable 接口中的 compareTo方法
    	@Override
    	public int compareTo(Object o) {
    		
    		return this.age-((User)o).age;
    	}
    }
    

    這樣就可以成功運行了,輸出結構是按照年齡從小到大排序的

    User[age=10]
    User[age=11]
    User[age=12]
    User[age=13]
    User[age=15]
    
  • SortedSet集合做到排序還有另一種方式:java.util.Comparator

    • 單獨編寫一個比較器,傳入到TreeSet對象中。
    • 比較推薦此類寫法,因爲不需要改變存入SortedSet內元素的類,具有更低的耦合性

    單獨編寫比較器,傳入到TreeSet構造函數裏面

    
    import java.util.*;
    
    public class Test13 {
    	public static void main(String[] args) {
    		@SuppressWarnings("unchecked")
    		SortedSet ss = new TreeSet(new ProductComparator());
    		Product p1 = new Product(32);
    		Product p2 = new Product(12);
    		Product p3 = new Product(24);
    		Product p4 = new Product(13);
    		ss.add(p1);
    		ss.add(p2);
    		ss.add(p3);
    		ss.add(p4);
    		// 遍歷
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    	}
    }
    
    class Product{
    	double price;
    	public Product(double price) {
    		this.price = price;
    	}
    	@Override
    	public String toString() {
    		return "Product["+this.price+"]";
    	}
    	
    }
    class ProductComparator implements Comparator{
    
    	@Override
    	public int compare(Object o1, Object o2) {
    		if(o1 instanceof Product && o2 instanceof Product) {
    			double price1 = ((Product)o1).price;
    			double price2 = ((Product)o2).price;
    			if(price1 == price2) {
    				return 0;
    			}else if(price1 > price2) {
    				return 1;
    			}else {
    				return -1;
    			}
    		}
    		return 0;
    	}
    	
    }
    

    也可以使用匿名內部類

    import java.util.*;
    
    public class Test13 {
    	public static void main(String[] args) {
    		@SuppressWarnings("unchecked")
    		SortedSet ss = new TreeSet(new Comparator() {// 匿名內部類
    			@Override
    			public int compare(Object o1, Object o2) {
    				double price1 = ((Product)o1).price;
    				double price2 = ((Product)o2).price;
    				if(price1 == price2) {
    					return 0;
    				}else if(price1 > price2) {
    					return 1;
    				}else {
    					return -1;
    				}
    			}
    		});
    		Product p1 = new Product(32);
    		Product p2 = new Product(12);
    		Product p3 = new Product(24);
    		Product p4 = new Product(13);
    		ss.add(p1);
    		ss.add(p2);
    		ss.add(p3);
    		ss.add(p4);
    		// 遍歷
    		Iterator it = ss.iterator();
    		while(it.hasNext()) {
    			System.out.println(it.next());
    		}
    	}
    }
    
    class Product{
    	double price;
    	public Product(double price) {
    		this.price = price;
    	}
    	@Override
    	public String toString() {
    		return "Product["+this.price+"]";
    	}
    	
    }
    

    輸出結果:// 已經排序了

    Product[12.0]
    Product[13.0]
    Product[24.0]
    Product[32.0]
    

集合中 Map 的繼承結構圖(重要)

  • MapCollection 沒有關係

Map的繼承結構圖

  • Map是一個父接口,HashMap類和Hashtable類實現了Map接口,SortedMap接口繼承Map接口,TreeMap類實現了SortedMap接口

  • HashMap中的 key 要重寫 hashCode()equals()方法

  • SortedMap或者TreeMapkey要實現Comparable接口中的compareTo() 方法。或者單獨寫一個Comparator比較器

  • Properties 類繼承自 Hashtable,是一個屬性類,也是以key-value的方式存儲元素,但是key-value只能是字符串

Map集合中常用的方法

  • 存儲在Map集合中的 key 部分的元素需要同時重寫 hashCode()equals()方法。
void clear();
boolean	isEmpty();
int	size();

V	get(Object key);
V	put(K key, V value);	// 注意:map中如果key重複了,value將會覆蓋key對應的值

boolean	containsKey(Object key);
boolean	containsValue(Object value);

V	remove(Object key);

Set keySet();
Collection values();
Set entrySet()
import java.util.*;

public class Test14 {
	public static void main(String[] args) {
		// 1.創建集合
		Map persons = new HashMap();
		// 2. 存儲鍵值對
		persons.put("10000", "Javk");
		persons.put("10001", "Cook");
		persons.put("10002", "Book");
		persons.put("10003", "Kook");
		persons.put("10004", "Pook");
		persons.put("10002", "BooJ");
		// 3. 判斷鍵值對的個數
		// Map 中的key是無序的不可重複的
		System.out.println(persons.size());// 5
		// 4. 判斷Map中是否包含某key
		System.out.println(persons.containsKey("10003"));// true
		// 5. 判斷Map中是否包含某value
		System.out.println(persons.containsValue("Javk"));// true
		System.out.println(persons.containsValue("Book"));// false
		// 6. 通過 key 獲取value
		String key = "10002";
		Object value = persons.get(key);
		System.out.println(value);// BooJ  // BooJ將Book覆蓋掉了
		// 7. 通過key刪除鍵值對
		persons.remove("10004");
		System.out.println(persons.size());// 4
		// 8. 獲取所有的value
		Collection values = persons.values();
		Iterator it = values.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
		// 9. 獲取所有的 key
		Set keys = persons.keySet();
		it = keys.iterator();
		while(it.hasNext()) {
			Object id = it.next();
			Object name = persons.get(id);
			System.out.println(id+"-->"+name);
		}
		// 10. entrySet
		Set entrySet = persons.entrySet();
		it = entrySet.iterator();
		while(it.hasNext()) {
			System.out.println(it.next());
		}
	}
}

Hashtable & Properties常用方法介紹

  • Hashtable 是線程安全的,但是效率低

    • 初始化容量是 11, 加載因子是 0.75
    • HashMap的初始化容量是 16, 加載因子是 0.75
  • Properties 是一個屬性類,繼承自 Hashtable類,存儲的key-value 只能是字符串

    import java.util.*;
    
    public class Test15 {
    	public static void main(String[] args) {
    		// 1.創建屬性類對象
    		Properties p = new Properties();
    		// 2. 存儲元素
    		p.setProperty("driver", "oracle.jdbc.driver.OracleDriver");
    		p.setProperty("username", "tailor");
            // 注意 key 不能重複,如果重複則覆蓋原來的value
            p.setProperty("username", "tailor95");
    		p.setProperty("password", "balabala");
    		p.setProperty("url", "jdbc:oracle:thin:@192.168.1.100:1512:balabala");
    		
    		// 3. 通過 key 獲取 value
    		String v1 = p.getProperty("driver");
    		String v2 = p.getProperty("username");
    		String v3 = p.getProperty("password");
    		String v4 = p.getProperty("url");
    		
    		System.out.println(v1);
    		System.out.println(v2);
    		System.out.println(v3);
    		System.out.println(v4);
    	}
    }
    

    輸出:

    oracle.jdbc.driver.OracleDriver
    tailor95
    balabala
    jdbc:oracle:thin:@192.168.1.100:1512:balabala
    

SortedMap & TreeMap

  • SortedMapkey 的特點:無序不重複,但是存進去的元素可以按照大小自動排序

    • 如果想自動排序,key部分的元素需要:或者實現 Comparable 接口, 或者單獨實現一個比較器 Comparator
      • 下面代碼是 實現了 Comparable接口
    import java.util.*;
    
    public class Test16 {
    	public static void main(String[] args) {
    		// Map 中的key 存儲 product, value存儲 重量
    		// 1. 創建 map集合
    		SortedMap sm = new TreeMap();
    		// 2. 準備 對象
    		ProductMap p1 = new ProductMap("西瓜", 0.5);
    		ProductMap p2 = new ProductMap("蘋果", 3.0);
    		ProductMap p3 = new ProductMap("香蕉", 2.0);
    		ProductMap p4 = new ProductMap("橘子", 1.5);
    		// 3. 添加到map中
    		sm.put(p1, 8.0);
    		sm.put(p2, 5.0);
    		sm.put(p3, 2.0);
    		sm.put(p4, 3.0);
    		// 4. 遍歷
    		Iterator it = sm.keySet().iterator();
    		while(it.hasNext()) {
    			Object p = it.next();
    			Object w = sm.get(p);
    			System.out.println(p+"===>"+w);
    		}
    	}
    }
    
    class ProductMap implements Comparable{// 實現 Comparable接口
    	String name;
    	double price;
    	public ProductMap(String name, double price) {
    		this.name = name;
    		this.price = price;
    	}
    	// 重寫 toString
    	@Override
    	public String toString() {
    		return "[Product:"+this.name+"--->"+this.price+"]";
    	}
    	@Override
    	public int compareTo(Object o) {
    		double price1 = this.price;
    		double price2 = ((ProductMap)o).price;
    		if(price1 > price2) {
    			return 1;
    		}else if(price1 < price2) {
    			return -1;
    		}else return 0;
    	}
    	
    }
    
    • 下面代碼是單獨實現了一個比較器Comparator(使用了匿名內部類)

      package com.test.collections;
      
      import java.util.*;
      
      public class Test16 {
      	public static void main(String[] args) {
      		// Map 中的key 存儲 product, value存儲 重量
      		// 1. 創建 map集合
      //		SortedMap sm = new TreeMap();
      		SortedMap sm = new TreeMap(new Comparator() {// 單獨實現了一個比較器
      
      			@Override
      			public int compare(Object o1, Object o2) {
      				double price1 = ((ProductMap)o1).price;
      				double price2 = ((ProductMap)o2).price;
      				if(price1 > price2) {
      					return 1;
      				}else if(price1 < price2) {
      					return -1;
      				}else return 0;
      			}
      			
      		});
      		// 2. 準備 對象
      		ProductMap p1 = new ProductMap("西瓜", 0.5);
      		ProductMap p2 = new ProductMap("蘋果", 3.0);
      		ProductMap p3 = new ProductMap("香蕉", 2.0);
      		ProductMap p4 = new ProductMap("橘子", 1.5);
      		// 3. 添加到map中
      		sm.put(p1, 8.0);
      		sm.put(p2, 5.0);
      		sm.put(p3, 2.0);
      		sm.put(p4, 3.0);
      		// 4. 遍歷
      		Iterator it = sm.keySet().iterator();
      		while(it.hasNext()) {
      			Object p = it.next();
      			Object w = sm.get(p);
      			System.out.println(p+"===>"+w);
      		}
      	}
      }
      
      class ProductMap{
      	String name;
      	double price;
      	public ProductMap(String name, double price) {
      		this.name = name;
      		this.price = price;
      	}
      	// 重寫 toString
      	@Override
      	public String toString() {
      		return "[Product:"+this.name+"--->"+this.price+"]";
      	}
      
      }
      

      輸出:可見key按照價格排了序

      [Product:西瓜--->0.5]===>8.0
      [Product:橘子--->1.5]===>3.0
      [Product:香蕉--->2.0]===>2.0
      [Product:蘋果--->3.0]===>5.0
      

關於集合工具類Collections的用法

  • java.util.Collections 是一個類,是集合的工具類,可以實現對集合的操作

    -java.util.Collection 是一個接口

  • Collections 裏面的 sort方法,實現集合內的元素的排序

    static void	sort(List list)
    
    • 示例1

      import java.util.*;
      
      public class Test17 {
      	public static void main(String[] args) {
      		// 1. 創建List集合
      		List l = new ArrayList();
      		// 2. 添加元素
      		l.add(10);
      		l.add(20);
      		l.add(14);
      		l.add(23);
      		// 3. 遍歷
      		for(int i=0; i<l.size(); i++) {
      			System.out.println(l.get(i));
      		}
      		// 調用 Collcetions類中的 sort方法排序
      		Collections.sort(l);
      		// 遍歷
      		System.out.println("=========");
      		for(Iterator it = l.iterator();it.hasNext();) {
      			System.out.println(it.next());
      		}
      	}
      }
      
      

      輸出:

      10
      20
      14
      23
      =========
      10
      14
      20
      23
      
    • Collcetions 類中的 sort() 方法怎麼對集合中的元素進行排序?

      • Set集合轉換爲List類型

      Set類型轉換爲List類型-通過ArrayList構造方法

      import java.util.*;
      
      public class Test18 {
      	public static void main(String[] args) {
      		// 1. 創建set集合
      		Set s = new HashSet();
      		// 2. 添加元素
      		s.add(12);
      		s.add(10);
      		s.add(21);
      		s.add(32);
      		// 3. 創建List###########就是在這操作的###############
      		List list = new ArrayList(s);
      		// 4. 調用Collections工具類中的sort()方法進行排序
      		Collections.sort(list);
      		// 5. 遍歷
      		Iterator it = list.iterator();
      		while(it.hasNext()) {
      			System.out.println(it.next());
      		}
      	}
      }
      
      
    • 是不是List中存儲的所有類型的元素都可以調用Collections類中的sort方法?

      • 當然不是,元素要麼實現Comparable接口,要麼單獨寫一個比較器Comparator
        • 下面代碼運行錯誤:java.lang.ClassCastException: Person cannot be cast to java.lang.Comparable
          • 需要實現 Comparable接口
      import java.util.*;
      
      public class Test19 {
      	public static void main(String[] args) {
      		// 創建集合
      		List list = new ArrayList();
      		// 準備數據
      		Person p1 = new Person(); 
      		Person p2 = new Person(); 
      		Person p3 = new Person(); 
      		Person p4 = new Person();
      		// 添加數據
      		list.add(p1);
      		list.add(p2);
      		list.add(p3);
      		list.add(p4);
      		// 調用Collections類中的sort方法
      		Collections.sort(list);
      		// 遍歷輸出
      		Iterator it = list.iterator();
      		while(it.hasNext()) {
      			System.out.println(it.next());
      		}
      	}
      }
      
      class Person{
          // 沒有實現 Comparable
      }
      
      • 實現 Comparable接口

        package com.test.collections;
        import java.util.*;
        
        public class Test19 {
        	public static void main(String[] args) {
        		// 創建集合
        		List list = new ArrayList();
        		// 準備數據
        		Person p1 = new Person(); 
        		Person p2 = new Person(); 
        		Person p3 = new Person(); 
        		Person p4 = new Person();
        		// 添加數據
        		list.add(p1);
        		list.add(p2);
        		list.add(p3);
        		list.add(p4);
        		// 調用Collections類中的sort方法
        		Collections.sort(list);
        		// 遍歷輸出
        		Iterator it = list.iterator();
        		while(it.hasNext()) {
        			System.out.println(it.next());
        		}
        	}
        }
        
        class Person implements Comparable{
        
        	@Override
        	public int compareTo(Object o) {
        		return 0;
        	}
        	
        }
        
    • Collections 類中的 synchronizedList(List list)方法可以將線程不安全的 ArrayList轉換成線程安全的

      import java.util.*;
      public class Test20 {
      	public static void main(String[] args) {
      		List list = new ArrayList();
      		Collections.synchronizedList(list);
      		// 這之後,list就是線程安全的了
      	}
      }
      
      

泛型初步

主要介紹jdk5.0的新特性: 泛型(屬於編譯期的概念)

爲什麼引入泛型

  • 可以統一集合中的數據類型
  • 可以減少強制類型轉換

泛型語法如何實現

  • 泛型是編譯階段的語法,在編譯階段統一集合中的數據類型

    • List使用泛型
    import java.util.*;
    
    public class Test21 {
    	public static void main(String[] args) {
    		// 創建泛型集合// 創建String類型的集合
    		List<String> list = new ArrayList<String>();
    		// 添加元素
    		//list.add(1);// 編譯錯誤 list中存儲的是String類型,所以不能添加 Integer 類型的數據
    		list.add("Jack");
    		list.add("Tom");
    		list.add("Jerry");
    		list.add("Snobe");
    		// 遍歷泛型集合
    		Iterator<String> it = list.iterator();
    		while(it.hasNext()) {
    			String s = it.next();
    			System.out.println(s);
    		}
    	}
    }
    
    • Map使用泛型

      import java.util.*;
      public class Test22 {
      	public static void main(String[] args) {
      		// 創建集合
      		Map<String, Integer> maps = new HashMap<String, Integer>();
      		// 添加元素
      		maps.put("蘋果", 23);
      		maps.put("橘子", 18);
      		maps.put("香蕉", 3);
      		maps.put("西瓜", 64);
      		// 遍歷
      		// 得到所有的key
      		Set<String> keys = maps.keySet();
      		Iterator<String> it = keys.iterator();
      		while(it.hasNext()) {
      			String key = it.next();
      			Integer i = maps.get(key);
      			System.out.println(key+"--->"+i);
      		}
      	}
      }
      
      
    • SortedSet 使用泛型

      • 注意實現 Comparable 接口
      import java.util.*;
      public class Test23 {
      	public static void main(String[] args) {
      		// 創建集合
      		SortedSet<Manager> ss = new TreeSet<Manager>();
      		// 準備數據
      		Manager m1 = new Manager(23.0);
      		Manager m2 = new Manager(22.0);
      		Manager m3 = new Manager(23.4);
      		Manager m4 = new Manager(12.0);
      		Manager m5 = new Manager(18.5);
      		ss.add(m1);
      		ss.add(m2);
      		ss.add(m3);
      		ss.add(m4);
      		ss.add(m5);
      		// 遍歷數據
      		Iterator<Manager> it = ss.iterator();
      		while(it.hasNext()) {
      			it.next().work();
      		}
      	}
      }
      class Manager implements Comparable<Manager>{ // 實現 Comparable接口
      	double sal;
      	public Manager(double sal) {
      		this.sal = sal;
      	}
      	public void work() {
      		System.out.println("工作,一個月"+sal+"元");
      	}
      	@Override
      	public String toString() {
      		return sal+"";
      	}
      	@Override
      	public int compareTo(Manager o) {
      		if(this.sal > o.sal) {
      			return 1;
      		}else if(this.sal < o.sal) {
      			return -1;
      		}
      		return 0;
      	}
      
      	
      }
      

自定義泛型


public class Test24 {
	public static void main(String[] args) {
		MyClass<String> mc = new MyClass<String>();
//		mc.m1(100);// 編譯錯誤
		mc.m1("Jack");;
	}
}
class MyClass<T>{
	void m1(T t) {
		System.out.println(t);
	}
}

泛型的優點和缺點

  • 優點:同一類型,減少強制轉換
  • 缺點:只能存儲一種類型

forEach

關於增強 for 循環(JDK5.0新特性)

語法:

for(類型 變量:數組名/集合名){}
  • 集合如果想使用 **增強for**循環這種語法,集合需要使用 泛型

    • 不使用泛型也可以,但是for裏面的變量類型應該是 Object
    import java.util.*;
    
    public class Test25 {
    	public static void main(String[] args) {
    		int[] a= {1,2,3,4};
    		for(int e: a) {
    			System.out.println(e);
    		}
    		System.out.println("==========");
    		// 集合
    		Set<String> s = new HashSet<String>();
    		s.add("張三");
    		s.add("李四");
    		s.add("王五");
    		s.add("趙六");
    		// 遍歷
    		for(String name:s) {
    			System.out.println(name);
    		}
    	}
    }
    
  • 增強for循環的缺點:

    • 沒有下標

end

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章