Java學習----Collection總結

Java----Collection總結

集合,存儲多個元素的容器----大小不定。
在集合這塊主要的內容有:
接口:Collection Iterator List   Set  Map
類:ArrayList   LinkedList  stack queue
hashMap  hashTable


本篇爲Collection的總結,纔開始學習Java,在集合這塊看資料總是感覺一團亂麻。所以寫這個總結,一方面把自己知道的東西梳理一下,另一方面初學水平有限,如果有錯誤還請各位大神能夠指點,還有就是剛開始玩社區,希望能夠獲取一點積分,嘿嘿。希望有一天,能夠學習JAVA,加入Ali。

Collection接口

Collection是集合層次的根接口。由於泛型的限制,集合中只能存儲對象。泛型只能表示引用類型。
Collection定義中的主要方法,就是說當要實現一個Collection的時候,要先實現以下方法(不全,可以查看API穩定):


public interface Collection<E> extends Iterable<E>{
  int size();
  boolean isEmpty();
  void clear();
  boolean contains();
  boolean add();
  boolean remove();
  Iterator<E> iterator();
}


實現一個Collection,在ArrayList中實現了List接口,而List接口繼承了Collection接口,所以可以用下面方式來實現一個Collection集合,然後可以用上述方法。
Collection<String> c = new ArrayList<String>();


List接口

List接口是Collection的子接口,用於定義線性表數據結構。可以將List理解爲存放對象的動態數組,只不過其元素個數可以動態的增加或者減少。List接口兩個常見的實現類是ArrayList和LinkedList。分別用動態數組和鏈表的方式實現了List接口。(這兩種實現方式在文末附上)

public interface List<E> extends Collection<E> {
Anytype get(int idx);
  Anytype set(int idx, Anytype newVal);
  void add(int idx, Anytype x);
  void remove(int idx);
  Iterator<Integer> listIterator(int pos);
}


重要方法:

List<E> list = new ArrayList<>();
E get(int idx) 獲取集合中指定下標對應的元素
E set(int idx,E element) 給定下標上的元素,並將原來的元素返回
E add(int idx,E element) 在給定下標出添加元素,原位置及以後的元素都後移
E remove(int idx) 刪除給定位置的元素,並將被刪除的元素返回
List<E> sublist(int formIdx,int toIdx)獲得List中的子序列(前包括,後不包括)

Object[] toArray()
<T> [] t  =  toArray(T[] a) 
String [] strArr = list.toArray(new String []()); 將List轉成數組,第二種比較常用

static List<T> list = asList<T[]a>
String [] strArr = {"a","b","c"};
  List<String> list = Arrays.asList(strArr);將數組轉換成list。

Iterator接口

public interface Iterator<E> {
  boolean hasNext();
  Anytype next();
  void remove();
}

迭代器用於遍歷集合元素。獲取迭代器,可以使用Collection中的方法,Iterator iterator()。具體用法如下代碼。:

Set<String> set = new HashSet<String>();
  set.add("a");
  set.add("b");
  //建立一個指向set的迭代器
  Iterator<String> it = set.iterator();
  while(it.hasNext()){ 
   String str = it.next();
   System.out.println(str);
   //刪除元素
   it.remove();
  }
 System.out.println(set);
注意:迭代器在遍歷元素時,不能通過集合的remove方法來刪除元素,否則會拋出異常。但是可以通過迭代器自身提供的方法的remove方法來刪除,具體實現方式在LinkedList的實現代碼中有。 


Collections 操作集


Collections操作集是爲collection及其子接口、類提供操作方法的一個操作集。(幾乎用不到)但是有sort()方法比較重要。
void sort(List<T> list);
直接使用該方法是自然排序,也可以使用Comparable 和Comparator。
Collection中的sort()能夠排序的主要原因是,傳入的集合元素都是Comparable接口的實現類,該接口表示子類是可以比較的,因爲實現該接口重寫抽象方法 int compareTo(T t);
該方法用於當前對象與給定對象進行比較:
 若當前對象大於給定對象,則返回值應爲大於0的整數
 若當前對象小於給定對象,則返回值應爲小於0的整數
 若兩個對象相等,則返回值等於0
一旦java類實現了comparable接口,其比較規則就已經確定。如果想要在排序中臨時指定規則,可以採用Comparator接口回調的方式,具體使用如下:

list.sort(new Comparator<String>(){
   //比較規則寫在這
   //如果返回值>0,那麼就會將o2排在o1之前
   //如果返回值<0,那麼就會將o1排在o2之前
   public int compare(String o1,String o2){
    //return o1.compareTo(o2);
    return o1.charAt(0) - o2.charAt(0);
   }
  });

Set接口--散列集合

不包含重複元素的集合(唯一)
Set的具體用法跟list差不多,這裏代碼不再重複寫。
Set<String> set = new HashSet<String>();
HashSet
底層基於hashMap來進行存儲,不保證迭代順序,並且不保證循序不變。
HashMap
是基於數組+鏈表來進行存儲。底層數組初始容量爲16.數組中的每一個位置稱之爲是一個桶-bucket
O1---先計算o1的hash碼--哈希碼是int類型的整數--針對哈希碼進行二次運算,使運算結果落在桶的編號之中。
每一個桶中維繫了一個鏈表。添加新元素時,先比較與桶中的元素是否相等,不相等,加入到鏈表,有相等就捨棄。放的越晚的元素,比較就越低,增刪改效率都會降低。所以想要縮短鏈的長度,就得增加桶的個數。擴容,每次都是一倍。
如果已經使用的桶的數量/桶的總數量>加載因子,那麼就認爲需要擴容。默認加載因子是0.75。擴容之後,會對桶中的元素進行重新的計算和分佈,是元素散列在新找的桶中--rehash。
Rehash---元素越多,效率越低。當你進行rehash的時候,是不能往裏面放元素的。
加載因子:影響擴容,越小會擴容越頻繁。同時會導致內存的浪費。效率變低。加載因子越大,會導致每一個桶匯中的鏈表會變長而導致查找變慢。
public HashSet(int initialCapacity),允許指定初始容量和加載因子。
總的效率,一開始是高的,然後慢慢變慢。在JDK1.8中,如果鏈的長度>8,那麼會將這個鏈扭轉成紅黑樹,自平衡二叉樹。紅黑樹,比節點小,往左放,比節點大,往右放,類似二分查找。如果紅黑紅樹的節點個數<=6,會扭回鏈表。

Map接口

一組自變量按照某種規則變成另外一組因變量,就叫做映射。
K -key-鍵,V-value-值。一個鍵對應一個值 - 鍵值對。也就意味着,一個映射實際上是由多個鍵值對組成。在映射中,鍵是唯一的。一個鍵最多隻能對應一個值。
實現類HashMap與HashTab

HashMap<K,V>

底層是基於數組+鏈表的結構。允許鍵或者值爲null。默認初始容量是16,加載因子是0.75.。這個類不保證數據的順序map是計算key的哈希碼,可以針對哈希碼來進行二次運算,決定存到哪個桶中。尤其是不保證這個順序恆久不變。默認rehash擴容,每次會增加大約兩倍空間。如果是一個比較高的加載因子,
hashMap允許指定初始容量。指定的初始容量在[2^x , 2^x+1]之間,那麼容量算出來的一定是爲2^x+1。指定這麼大是爲了擴容的時候,直接左移一位。本身是一個異步式線程不安全的映射。
異步式:如果一個對象在同一個時刻內允許多人操作
同步式:如果一個對象在一個時刻內允許一個人操作

Map<String, Integer> map = new HashMap<>();
  map.put("d",6);
  map.put("e",4);
  map.put("s",3);
  map.put("f",9);
map.put("i",4);
  //如果鍵值相同,對應的值覆蓋
  map.put("i", 3);
  
  //判斷是否包含這個鍵
  System.out.println(map.containsKey("a"));
  System.out.println(map.containsValue(7));
  //移除鍵值對
  map.remove("i");
  //如果鍵相同,那麼對應的值覆蓋
  
  //清空映射
  map.clear();
  
  //獲取指定的鍵所對應的值
  System.out.println(map.get("r"));
  
  //將映射中所有的值放入一個集合返回
  Collection<Integer> c = map.values();
 System.out.println(c);

HashTbale

不允許鍵或者值爲null.底層也是基於數組+鏈表。底層的默認初始容量是11.加載因子爲0.75F,默認擴容增加一倍,然後再+1。(官方沒有解釋爲什麼這樣)
這個映射本身是一個同步式線程安全的映射。
指定初始容量,指定多少,就是多少。
基本上沒有用,效率比較低,只會出現在面試的時候。

List接口 自己寫的LinkedList的實現


package ADT;

import java.security.NoSuchAlgorithmException;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.lang.String;

public class myLinkedList<String> implements Iterable<String> {

	private static class Node<String> {
		public Node(String d, Node<String> p, Node<String> n) {
			data = d;
			prev = p;
			next = n;
		}

		public String data;
		public Node<String> prev;
		public Node<String> next;

	}

	public myLinkedList() {
		doclear();
	}

	public void clear() {
		doclear();
	}

	public void doclear() {
		beginMarker = new Node<String>(null, null, null);
		endMarker = new Node<String>(null, beginMarker, null);
		beginMarker.next = endMarker;

		theSize = 0;
		modCount++;
	}

	public int size() {
		return theSize;
	}

	public boolean isEmpty() {
		return size() == 0;
	}

	public boolean add(String x) {
		add(size(), x);
		return true;
	}

	public void add(int idx, String x) {
		addBefore(getNode(idx, 0, size()), x);
	}

	public String get(int idx) {
		return getNode(idx).data;
	}

	public String set(int idx, String val) {
		Node<String> p = getNode(idx);
		String oldval = p.data;
		p.data = val;
		return oldval;
	}

	public String remove(int idx) {
		return remove(getNode(idx));
	}

	private void addBefore(Node<String> p, String x) {
		Node<String> newnode = new Node<>(x, p.prev, p);
		newnode.prev.next = newnode;
		p.prev = newnode;
		theSize++;
		modCount++;
	}

	private String remove(Node<String> p) {
		p.prev.next = p.next;
		p.next.prev = p.prev;
		theSize--;
		modCount++;
		return p.data;
	}

	private Node<String> getNode(int idx) {
		return getNode(idx, 0, size() - 1);
	}

	private Node<String> getNode(int idx, int low, int up) {
		Node<String> p;
		if (idx < low || idx > up) {
			throw new IndexOutOfBoundsException();
		}
		if (idx < size() / 2) {
			p = beginMarker;
			for (int i = 0; i < idx; i++)
				p = p.next;
		} else {
			p = endMarker;
			for (int i = size(); i > idx; i--)
				p = p.prev;
		}
		return p;
	}

	@Override
	public Iterator<String> iterator() {
		// TODO Auto-generated method stub
		return new LinkedIterator();
	}

	private class LinkedIterator implements Iterator<String> {
		private Node<String> current = beginMarker.next;
		private int exceptedModecount = modCount;
		private boolean okToRemove = false;

		@Override
		public boolean hasNext() {
			// TODO Auto-generated method stub
			return current != endMarker;
		}

		@Override
		public String next() {
			// TODO Auto-generated method stub
			if (modCount != exceptedModecount)
				throw new ConcurrentModificationException();
			if (!hasNext())
				throw new NoSuchElementException();
			String nextItem = current.data;
			current = current.next;
			okToRemove = true;
			return nextItem;
		}

		public void remove() {
			if (modCount != exceptedModecount)
				throw new ConcurrentModificationException();
			if (!okToRemove)
				throw new IllegalStateException();
			myLinkedList.this.remove(current.prev);
			exceptedModecount++;
			okToRemove = false;
		}

	}

	@Override
	public java.lang.String toString() {

		StringBuilder sb = new StringBuilder("[");

		Node node = this.beginMarker;
		while (node != null) {

			sb.append(node.data).append(", ");
			node = node.next;

		}

		java.lang.String str = sb.toString();
		if (size() != 0)
			str = str.substring(0, str.length() - 2);

		return str += "]";
	}

	private Node<String> beginMarker;
	private Node<String> endMarker;
	private int theSize;
	private int modCount = 0;
}


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