如何選擇?
一、容器類和Array的區別、擇取
* 容器類僅能持有對象引用(指向對象的指針),而不是將對象信息copy一份至數列某位置。
* 一旦將對象置入容器內,便損失了該對象的型別信息。
二、
* 在各類Lists中,最好的作法是以ArrayList做爲缺省選擇。當插入、刪除頻繁時,使用LinkedList();
Vector老是比ArrayList慢,因此要儘可能避免使用。
* 在各類Sets中,HashSet一般優於TreeSet(插入、查找)。只有當須要產生一個通過排序的序列,才用TreeSet。
TreeSet存在的惟一理由:可以維護其內元素的排序狀態。
* 在各類Maps中
HashMap用於快速查找。
* 當元素個數固定,用Array,由於Array效率是最高的。
結論:最經常使用的是ArrayList,HashSet,HashMap,Array。並且,咱們也會發現一個規律,用TreeXXX都是排序的。
注意:
一、Collection沒有get()方法來取得某個元素。只能經過iterator()遍歷元素。
二、Set和Collection擁有如出一轍的接口。
三、List,能夠經過get()方法來一次取出一個元素。使用數字來選擇一堆對象中的一個,get(0)...。(add/get)
四、通常使用ArrayList。用LinkedList構造堆棧stack、隊列queue。
五、Map用 put(k,v) / get(k),還可使用containsKey()/containsValue()來檢查其中是否含有某個key/value。
HashMap會利用對象的hashCode來快速找到key。
* hashing
哈希碼就是將對象的信息通過一些轉變造成一個獨一無二的int值,這個值存儲在一個array中。
咱們都知道全部存儲結構中,array查找速度是最快的。因此,能夠加速查找。
發生碰撞時,讓array指向多個values。即,數組每一個位置上又生成一個槤表。
六、Map中元素,能夠將key序列、value序列單獨抽取出來。
使用keySet()抽取key序列,將map中的全部keys生成一個Set。
使用values()抽取value序列,將map中的全部values生成一個Collection。
爲何一個生成Set,一個生成Collection?那是由於,key老是獨一無二的,value容許重複。java
Java集合就是一個容器。面嚮對象語言對事物的體現都是以對象的形式存在,因此爲了方便對多個對象的操做,就對對象進行存儲,集合就是存儲對象最經常使用的一種方式。集合只用於存儲對象,集合長度是可變的,集合能夠存儲不一樣類型的對象。若是往集合裏存放基本數據類型,在存取過程當中會有個自動裝箱和拆箱。數組
由於容器中數據結構不一樣,容器有不少種。不斷地將共性功能向上抽取,造成了集合體系,稱之爲集合框架。數據結構
集合框架的頂層就稱之爲Collection接口。全部的集合類都位於java.util包下,查閱API能夠獲得以下體系結構。在使用一個體系時,原則:參閱頂層內容。創建底層對象。框架
集合和數組的區別:less
1:數組是固定長度的;集合可變長度的。ide
2:數組能夠存儲基本數據類型,也能夠存儲引用數據類型;集合只能存儲引用數據類型。學習
3:數組存儲的元素必須是同一個數據類型;集合存儲的對象能夠是不一樣數據類型。ui
Collection<E>接口this
Collection:單列集合url
|--List:有序(元素存入集合的順序和取出的順序一致),元素都有索引,容許重複元素。
|--Set:無序(存入和取出順序有可能不一致),不容許重複元素,必須保證元素的惟一性。
java.util.Collection接口中的共性方法有:
1.添加:
boolean add(Object obj):一次添加一個。
boolean addAll(Collection c):將指定容器中的全部元素添加。
2.刪除:
void clear():將集合中的元素全刪除,清空集合。
boolean remove(Object o):刪除集合中指定的對象。注意:刪除成功,集合的長度會改變。
boolean removeAll(Collection c):刪除部分元素。部分元素和傳入Collection一致。
3.取交集:
boolean retainAll(Collection c):對當前集合中保留和指定集合中的相同的元素。
若是兩個集合元素相同,返回false;若是retainAll修改了當前集合,返回true。
4.獲取長度:
int size():集合中有幾個元素。
5.判斷:
boolean isEmpty():集合中是否有元素。
boolean contains(Object o):集合中是否包含指定元素。
boolean containsAll(Collection c)集合中是否包含指定的多個元素。
6.將集合轉成數組。
toArray()
toArray([])
package ustc.lichunchun.collection.demo;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionDemo {
public static void main(String[] args) {
Collection coll = new ArrayList();
methodDemo(coll);
System.out.println("------------------");
methodAllDemo();
}
/*
* 演示Collection中的基本功能。
*/
public static void methodDemo(Collection coll){
//1.添加元素。
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
//2.刪除
coll.remove("abc2");//移除和添加元素 --> 會改變集合的長度 --> 集合裏面實際上存的是對象們的引用
//3.清除。
coll.clear();
//4.判斷包含。
System.out.println("contains: "+coll.contains("abc1"));//底層實現判斷用的是equals()
System.out.println(coll);
}
/*
* 演示帶All的方法。
*/
public static void methodAllDemo(){
//1.建立兩個容器。
Collection c1 = new ArrayList();
Collection c2 = new ArrayList();
//2.添加元素。
c1.add("abc1");
c1.add("abc2");
c1.add("abc3");
c1.add("abc4");
c2.add("abc2");
c2.add("abc3");
c2.add("abc5");
//往c1中添加c2。
c1.addAll(c2);
//判斷c1中是否包含c2中的全部元素。
boolean b = c1.containsAll(c2);
System.out.println("b = "+b);
//從c1中刪除c2。將c1中和c2相同的元素從c1中刪除。
c1.removeAll(c2);
//將c1中和c2不一樣的元素從c1中刪除。保留c1中和c2相同的元素。
c1.retainAll(c2);
System.out.println(c1);
}
}
Collection 接口中明明沒有toString()聲明,怎麼可能有權利調用這個ArrayList類的"特有"方法? (雖然ArrayList類繼承它父類有toString()複寫的方法了,但這個是ArrayList子類特有的方法啊,不符合多態的解釋呀?)
樓主懂得思考,先表揚一下。下面將引用一段接口的說明,你能夠看看:
9.2 Interface Members
The members of an interface are:Those members declared in the interface.
Those members inherited from direct superinterfaces.
If an interface has no direct superinterfaces, then the interface implicitly declares a public abstract member method m with signature s, return type r, and throws clause t corresponding to each public instance method m with signature s, return type r, and throws clause t declared in Object, unless a method with the same signature, same return type, and a compatible throws clause is explicitly declared by the interface. It is a compile-time error if the interface explicitly declares such a method m in the case where m is declared to be final in Object.
大體意思以下:
9.2 接口方法
一個接口中的方法有:
1).直接聲明在接口中的成員方法;
2).直接從父類接口中繼承而來的方法;
3).若是一個接口沒有直接的父類接口(也就是其自身就是頂層接口),而且在其沒有顯示聲明相關方法時,那該接口則會根據Object中全部的public的實例方法進行一一映射(好比toString,Hashcode等)。固然若是此接口顯示去聲明一個與Object簽名相同而且帶有final修飾的方法時,則會有編譯期錯誤。
因此:由超類聲明,子類來new。調用的最終是子類中定義的方法,若是子類沒有,則調用子類的父類方法。這存在一種向上追溯的過程。說明是徹底正確的。
根據這一條說明,在List list=new ArrayList()以後,在list當中將能夠調用object當中全部聲明public的方法,而調用的方法實體是來自ArrayList的。而之因此沒有list不能夠調用,clone()與finalize()方法,只是由於它們是protected的。
學習了。
Iterator<E>接口
java.util.Iterator接口是一個對 collection 進行迭代的迭代器,做用是取出集合中的元素。
Iterator iterator():獲取集合中元素上迭代功能的迭代器對象。
迭代:取出元素的一種方式。有沒有啊?有!取一個。還有沒有啊?有!取一個。還有沒有啊?沒有。算了。
迭代器:具有着迭代功能的對象。迭代器對象不須要new。直接經過 iterator()方法獲取便可。
迭代器是取出Collection集合中元素的公共方法。
每個集合都有本身的數據結構,都有特定的取出本身內部元素的方式。爲了便於操做全部的容器,取出元素,將容器內部的取出方式按照一個統一的規則向外提供,這個規則就是Iterator接口。
也就說,只要經過該接口就能夠取出Collection集合中的元素,至於每個具體的容器依據本身的數據結構,如何實現的具體取出細節,這個不用關心,這樣就下降了取出元素和具體集合的耦合性。
Iterator it = coll.iterator();//獲取容器中的迭代器對象,至於這個對象是是什麼不重要。這對象確定符合一個規則Iterator接口。
package ustc.lichunchun.collection.demo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class IteratorDemo {
public static void main(String[] args) {
//1.建立集合。
Collection coll = new ArrayList();
coll.add("abc1");
coll.add("abc2");
coll.add("abc3");
//方式一:獲取該容器的迭代器。
Iterator it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
//方式二:直接for+alt+/,選擇第三個。
for (Iterator it = coll.iterator(); it.hasNext();) {
System.out.println(it.next());
}
System.out.println(it.next());//abc1
System.out.println(it.next());//abc2
System.out.println(it.next());//abc3
System.out.println(it.next());//java.util.NoSuchElementException
}
}
爲了下降容器的數據結構和取出容器元素的方法之間的耦合性,把訪問、取出容器元素的容器的內部類進行共性抽取,即各類容器的相應內部類都實現了Iterator接口,實現了hasNext()、next()、remove()方法。例如以下截取自ArrayList類的iterator()方法的底層實現代碼:
public Iterator<E> iterator() {
return new Itr();//取出ArrayList容器中元素的迭代器功能,返回的是一個Itr()迭代器對象,也就是實現Iterator接口的內部類對象。
}
/**
* An optimized version of AbstractList.Itr
*/
private class Itr implements Iterator<E> {//-->ArrayList容器的內部類,實現了Iterator迭代接口(迭代器),裏面有hasNext()、next()、remove()方法。
int cursor; // index of next element to return
int lastRet = -1; // index of last element returned; -1 if no such
int expectedModCount = modCount;
public boolean hasNext() {
return cursor != size;
}
@SuppressWarnings("unchecked")
public E next() {
checkForComodification();
int i = cursor;
if (i >= size)
throw new NoSuchElementException();
Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length)
throw new ConcurrentModificationException();
cursor = i + 1;
return (E) elementData[lastRet = i];
}
public void remove() {
if (lastRet < 0)
throw new IllegalStateException();
checkForComodification();
try {
ArrayList.this.remove(lastRet);
cursor = lastRet;
lastRet = -1;
expectedModCount = modCount;
} catch (IndexOutOfBoundsException ex) {
throw new ConcurrentModificationException();
}
}
@Override
@SuppressWarnings("unchecked")
public void forEachRemaining(Consumer<? super E> consumer) {
Objects.requireNonNull(consumer);
final int size = ArrayList.this.size;
int i = cursor;
if (i >= size) {
return;
}
final Object[] elementData = ArrayList.this.elementData;
if (i >= elementData.length) {
throw new ConcurrentModificationException();
}
while (i != size && modCount == expectedModCount) {
consumer.accept((E) elementData[i++]);
}
// update once at end of iteration to reduce heap write traffic
cursor = i;
lastRet = i - 1;
checkForComodification();
}
final void checkForComodification() {
if (modCount != expectedModCount)
throw new ConcurrentModificationException();
}
}
List<E>接口
List自己是Collection接口的子接口,具有了Collection的全部方法。List集合的具體子類:子類之因此區分是由於內部的數據結構(存儲數據的方式)不一樣。
List:有序(元素存入集合順序和取出一致),元素都有索引,容許重複元素-->自定義元素類型都要複寫equals方法。
|--Vector:底層的數據結構是數組。數組是可變長度的。線程同步的。增刪和查詢都巨慢!
|--ArrayList:底層的也是數組結構,也是長度可變的。線程不一樣步的,替代了Vector。增刪速度不快。查詢速度很快。(由於在內存中是連續空間)
|--LinkedList:底層的數據結構是鏈表,線程不一樣步的。增刪速度很快。查詢速度較慢。(由於在內存中須要一個個查詢、判斷地址來尋找下一元素)
可變長度數組的原理:
不斷new新數組並將原數組元素複製到新數組。即當元素超出數組長度,會產生一個新數組,將原數組的數據複製到新數組中,再將新的元素添加到新數組中。
ArrayList:是按照原數組的50%延長。構造一個初始容量爲 10 的空列表。
Vector:是按照原數組的100%延長。
首先學習List體系特有的共性方法,查閱方法發現List的特有方法都有索引(角標),這是該集合最大的特色。也就是說,List的特有方法都是圍繞索引(角標)定義的。
List集合支持對元素的增、刪、改、查。
1.添加(增):
add(index, element):在指定的索引位插入元素。
addAll(index, collection):在指定的索引位插入一堆元素。
2.刪除(刪):
remove(index):刪除指定索引位的元素。 返回被刪的元素。
3.獲取(查):
element get(index):經過索引獲取指定元素。
int indexOf(element):獲取指定元素第一次出現的索引位,若是該元素不存在返回—1;因此,經過—1,能夠判斷一個元素是否存在。
int lastIndexOf(element) :反向索引指定元素的位置。
List subList(start,end) :獲取子列表。
4.修改(改):
element set(index, newElement):對指定索引位進行元素的修改。
下面的代碼演示了List的特有方法:
package ustc.lichunchun.list.demo;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class ListDemo {
public static void main(String[] args) {
List list = new ArrayList();
methodDemo(list);
}
/*
* 演示List特有的方法。
*/
public static void methodDemo(List list){
//1.常規添加元素。
list.add("abc1");
list.add("abc2");
list.add("abc3");
//2.插入元素。
list.add(1,"hehe");
//3.刪除。
list.remove(1);
list.remove(1);
//4.獲取。
System.out.println(list.get(3));// java.lang.IndexOutOfBoundsException
System.out.println(list.get(1));
System.out.println(list.indexOf("abc3"));
//5.修改。
list.set(1,"keke");
System.out.println(list);
//6.取出集合中全部的元素。
for (Iterator it = list.iterator(); it.hasNext();) {
System.out.println("iterator: "+it.next());
}
//7.List集合特有的取出方式。遍歷。
for (int i = 0; i < list.size(); i++) {
System.out.println("get: "+list.get(i));
}
}
}
何時使用Map集合呢?
當需求中出現映射關係時,應該最早想到map集合。
package ustc.lichunchun.map;
import java.util.HashMap;
import java.util.Map;
import ustc.lichunchun.exception.NoWeekException;
public class MapTest {
public static void main(String[] args) {
/*
* 何時使用map集合呢?
* 當需求中出現映射關係時,應該最早想到map集合。
*/
String cnWeek = getCnWeek(3);
System.out.println(cnWeek);
String enWeek = getEnWeek(cnWeek);
System.out.println(enWeek);
}
/*
* 根據中文的星期,獲取對應的英文星期。
* 中文與英文相對應,能夠創建表,沒有有序的編號,只能經過map集合。
*/
public static String getEnWeek(String cnWeek){
//建立一個表。
Map<String,String> map = new HashMap<String, String>();
map.put("星期一","Monday");
map.put("星期二","Tuesday");
map.put("星期三","Wednesday");
map.put("星期四","Thursday");
map.put("星期五","Friday");
map.put("星期六","Saturday");
map.put("星期日","Sunday");
return map.get(cnWeek);
}
/*
* 根據用戶指定的數據獲取對應的星期。
*/
public static String getCnWeek(int num){
if (num>7 || num<=0)
throw new NotWeekException(num+", 沒有對應的星期");
String[] cnWeeks = {"","星期一","星期二","星期三","星期四","星期五","星期六","星期日"};
return cnWeeks[num];
}
}
package ustc.lichunchun.exception;
public class NotWeekException extends RuntimeException {
/**
*
*/
private static final long serialVersionUID = 1L;
public NotWeekException() {
super();
}
public NotWeekException(String message, Throwable cause,
boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
public NotWeekException(String message, Throwable cause) {
super(message, cause);
}
public NotWeekException(String message) {
super(message);
}
public NotWeekException(Throwable cause) { super(cause); } }