持有對象——Java容器

數組是保存一組基本數據類型的最優先選擇的數據結構,可是在某些狀況下須要保存一系列的自定義對象,Java提供了一套至關完整的容器類來結局這個問題(List、Set、Queue、Map)。這些容器均有本身的特點,如Set能夠保證保存的對象互異,Map保存k-v對(關聯數組)。容器類能夠自動調整本身的容量,所以在編程時,不用擔憂容器的容量問題(前提是你有足夠大的內存)。java

  1、泛型

容器類在默認狀況下是接收Object類的,換種說法,就是接收任何類型的類。泛型的做用就是在建立一個容器對象時,指定該容器對象接收的對象類型。例如:編程

package test;

import java.util.ArrayList;
/*
 * ArrayList不使用泛型,add()接收任何非法的類型。
 * orange能夠添加到apples中,編譯時無錯誤,運行時出現「類型轉換錯誤」。
 * */
public class AppleOrangeWithoutGeneric {
	public static void main(String[] args){
		ArrayList apples = new ArrayList();
		Apple apple = new Apple();
		Orange orange = new Orange();
		apples.add(apple);
		apples.add(orange);
		for (int i = 0; i<apples.size(); i++){
			((Apple)apples.get(i)).eat();
		}
	}
}

class Apple{
	public void eat(){}
}

class Orange{
	public void eat(){
		
	}
}

  在編譯時,以上示例代碼並沒有問題,可是會出現運行時錯誤,由於強制類型轉換是非法的。數組

比較安全一些的作法是在定義apples時指定該ArrayList只能接受Apple的對象。例如:安全

package test;

import java.util.ArrayList;

public class AppleOrangeWithGeneric {
	public static void main(String[] args){
		ArrayList<Apple> apples = new ArrayList<Apple>();
		Apple apple = new Apple();
		Orange orange = new Orange();
		apples.add(apple);
          //Compile error //apples.add(orange); for (int i = 0; i<apples.size(); i++){ ((Apple)apples.get(i)).eat(); } } } class Apple{ public void eat(){} } class Orange{ public void eat(){ } }

  2、分類

  1. Collection 保存獨立對象
    1. List:必須保持插入的順序保存數組
      1. LinkedList
      2. ArrayList
    2. Stack
    3. Set:不能有重複的元組
      1. HashSet
      2. TreeSet
    4. Queue
  2. Map:保存一組相關對象
    1. HashMap
    2. TreeMap

    List

    List有兩種基本的類型,LinkedList在隨機訪問方面先對比較慢,ArrayList適用於隨機訪問,可是中間插入和移除元素時比較慢。數據結構

    基本操做:add() get() equals() remove() retainAll() subList() containsAll() toArray()app

    迭代器能夠提升代碼複用程度。迭代器是一個隊形,他的工做原理是遍歷並選擇序列中的對象,使用迭代器能夠不用關心List的類型;dom

      1) 使用iterator()方法返回一個Iterator,準備返回序列中的第一個元素。優化

      2)使用next()方法得到當前位置的下一個元素。對象

      3)使用hasNext()方法判斷是否到達序列尾部。blog

      4)使用remove()方法將當前元素刪除。

    迭代器統一了對容器的訪問方式,使得遍歷序列的操做與程序底層的結構分離。

    

    ArrayList
    LinkedList

    使用方法較ArrayList更豐富,移除和插入效率更高。LinkedList添加了可使其用做棧、隊列或雙端隊列的方法。

    Stack

    先進後出,一種使用了LinkedList的實現:

package test;

import java.util.LinkedList;

public class StackTest {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Stack<String> stack = new Stack<String>();
		stack.push("str1");
		stack.push("str2");
		
		System.out.println(stack.pop());
		System.out.println(stack.pop());
	}

}

class Stack<T>{
	private LinkedList<T> storage = new LinkedList<T>();
	public void push(T t){storage.addFirst(t);}
	public T pop() {return storage.removeFirst();}
	public boolean isEmpty() {return storage.isEmpty();}
	public String toString() {return storage.toString();}
}

  Set

  Set不會保存重複的元素。Set最常被使用的場景是判斷歸屬性,使用Set能夠輕易地查詢某個對象是否存在某個Set中。HashSet專門對快速查找進行了優化。Set具備與Collection徹底同樣的接口,除此以外無其餘功能。

package test;

import java.util.*;
public class SetOfInteger {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Random rand = new Random(1);
		Set<Integer> set = new HashSet<Integer>();
		for(int i = 0; i<1000; i++){
			set.add(rand.nextInt(30));
		}
		System.out.println(set.toString());
	}

}

  輸出

[15, 8, 23, 16, 7, 22, 9, 21, 6, 1, 29, 14, 24, 4, 19, 26, 11, 18, 3, 12, 27, 17, 2, 13, 28, 20, 25, 10, 5, 0]

  即便在代碼中修改rand的seed值,輸出仍然不發生變化,但輸出的順序無規律可言。這是由於set在內部對所存儲的值進行了散列。TreeSet將元素維護在一顆紅黑樹中,所以想要得到有序的元素的話,最好使用TreeSet或者LinkedHaskSet:

 

package test;

import java.util.*;
public class TreeSetOfInteger {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Random rand = new Random(1);
		Set<Integer> set = new TreeSet<Integer>();
		for(int i = 0; i<1000; i++){
			set.add(rand.nextInt(30));
		}
		System.out.println(set.toString());
	}

}

輸出:

[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29]

 

   Queue

  隊列,典型的先進先出容器。LinkedList實現了Queue的接口,能夠向上轉型爲Queue。offer()方法將一個元素添加到隊尾。peek()和element()方法都在不移除的狀況下,返回隊頭,可是peek()在隊爲空時,返回null,後者在一樣狀況下返回nosuchelementexception。

  Map

  存儲k-v對。以下面例子,key爲某個數字,value是使用random產生的該數字的次數。

package test;
import java.util.*;
public class Statistics {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Random rand = new Random(100);
		Map<Integer,Integer> map = new HashMap<Integer,Integer>();
		for(int i = 0; i<1000;i++){
			int tmp = rand.nextInt(10);
			Integer count = map.get(tmp);
			map.put(tmp, count==null ? 1 : ++count);
		}
		System.out.println(map.toString());

	}

}

  輸出:

{2=96, 4=92, 9=102, 8=108, 6=99, 1=95, 3=105, 7=95, 5=99, 0=109}

  Map中的元素也能夠是Map,相似於多維數組。

總結

  • Collection保存單一的元素,Map保存k-v對。
  • 有了泛型,能夠指定容器存放數據的類型,避免強制類型轉換。
  • Collection和Map均可以自動調整內存。
  • List(Collection的導出類)有序,相似於數組,可用數字腳標訪問元素。
  • 大量隨機訪問使用ArrayList,大量增/刪操做使用LinkedList。
  • Queue和Stack的行爲時有LinkedList提供。
  • HashMap訪問速度快,TreeMap使用紅黑樹保證鍵的順序。LinkedHashMap提供了快速訪問並保留了有序。
  • Set中元素互異,HashSet提供最快的查詢速度,而TreeSet保持元素處於排序狀態。LinkedHashSet以插入順序保存元素。
  • 不建議使用Vector、HashTable、Stack

  

相關文章
相關標籤/搜索