前言:
在日常的開發(fā)中履婉,我們常常需要對多個對象做操作,對多條數(shù)據(jù)做記錄宣羊,為了更好的操作與記錄璧诵,iOS提供了數(shù)組(NSArray)、集合(NSSet)仇冯、字典(NSDictionary)之宿,他們可以統(tǒng)稱為集合,在Java中也提供了兩個接口--Collection接口與Map接口苛坚。Collection類似與iOS的array和set比被,Map類似與iOS的字典,今天主要聊聊Collection接口泼舱。
而Collection接口沒有直接的實現(xiàn)類等缀,其又定義了兩個子接口--List和Set接口,這兩個接口有各自的實現(xiàn)類娇昙。
一尺迂、List接口
Java中共有三個類實現(xiàn)了List接口,他們分別是ArrayList冒掌、LinkedList噪裕、Vector,list接口相比Set接口最大的區(qū)別就是List存儲的元素有序且可以重復(fù)而Set存儲的元素是無序且不能重復(fù)的宋渔。
ArrayList:
這里的ArrayList和iOS中的NSArray基本一致州疾,甚至方法也沒啥大差別辜限,基本上能望文知義皇拣,
比如add(E e)
、add(int index, E element)
薄嫡、addAll(Collection<? extends E> c)
氧急、set(int index, E e)
、get(int index)
毫深、size()
吩坝、remove(int index)
、clear()
哑蔫、toArray()
钉寝、clone()
等弧呐,但是感覺還是OC的命名風(fēng)格更好啊,因為Java單單看方法名區(qū)分被重載的方法很容易看混嵌纲,還要看下參數(shù)名才能明了俘枫,這里值得注意的是clone方法不知道是深拷貝還是淺拷貝,因為OC中是有兩者的區(qū)別的逮走,這個下次在做討論鸠蚪。
LinkedList:
LinkedList和ArrayList底層實現(xiàn)原理不一樣,LinkedList基于鏈表實現(xiàn)师溅,所以其刪除與增加元素速度會特別快茅信,畢竟只需要改個指針指向的元素就行,而基于數(shù)組實現(xiàn)的ArrayList每次刪除與增加元素墓臭,元素后面的元素全部得重新賦值蘸鲸。但是相比而言ArrayList的查詢速度明顯更快,因為數(shù)組在內(nèi)存中是有序且連續(xù)的窿锉,通過下標(biāo)和每個元素分配的大小能很容易找到相應(yīng)位置的元素棚贾。
Vector:
Vector是個非常古老的類,據(jù)說從JDK 1.0就已經(jīng)存在了榆综,Vector和上述兩個類最大的區(qū)別是他訪問數(shù)據(jù)是同步的妙痹,訪問Vector是線程安全的,Vector將對其做出的每個操作都加上了鎖鼻疮,而這些鎖從來不是必須的怯伊,你無法選擇加或者不加,所以他的性能損失很大判沟,現(xiàn)在很少有用到他的機會了耿芹。
二、Set接口
HashSet:
HashSet類直接實現(xiàn)了Set接口挪哄, 其底層其實是包裝了一個HashMap去實現(xiàn)的吧秕。HashSet采用HashCode算法來存取集合中的元素,因此具有比較好的讀取和查找性能迹炼。
據(jù)我所知這里和OC的NSSet基本也是一致的砸彬,存儲的元素不可重復(fù)、元素存儲無序斯入。他也是線程不安全的砂碉,另外和NSSet不同的一點是,Java的HashSet元素值可以為NULL刻两。
前面說到存儲的元素不可重復(fù)增蹭,那么HashSet是怎樣判斷元素不可重復(fù)的呢?
HashSet需要同時通過equals
和HashCode
來判斷兩個元素是否相等磅摹,具體規(guī)則是滋迈,如果兩個元素通過equals
為true霎奢,并且兩個元素的hashCode
相等,則這兩個元素相等(即重復(fù))饼灿。
LinkedHashSet:
LinkedHashSet是HashSet的一個子類椰憋,LinkedHashSet也根據(jù)HashCode的值來決定元素的存儲位置,但同時它還用一個鏈表來維護元素的插入順序赔退,插入的時候即要計算hashCode又要維護鏈表橙依,而遍歷的時候只需要按鏈表來訪問元素。
在最新的JDK1.8.0中硕旗,LinkedHashSet沒有定義任何方法窗骑,只有四個構(gòu)造函數(shù)和一個重載的迭代器,它的構(gòu)造函數(shù)調(diào)用了父類(HashSet)的帶三個參數(shù)的構(gòu)造方法漆枚。
TreeSet:
TreeSet實現(xiàn)了SortedSet接口(SortedSet繼承于Set接口)创译,顧名思義這是一種排序的Set集合,正因為它是排序了的墙基,所以相對HashSet來說软族,TreeSet提供了一些額外的按排序位置訪問元素的方法,例如first()残制、 last()立砸、lower()、higher()初茶、subSet()颗祝、headSet()、tailSet()
.
TreeSet的排序分兩種類型恼布,一種是自然排序螺戳,另一種是定制排序。
1.TreeSet-自然排序:
TreeSet 會調(diào)用compareTo
方法比較元素大小折汞。所以自然排序中的元素對象倔幼,都必須實現(xiàn)了Comparable接口,否則會跑出異常爽待。對于TreeSet判斷元素是否重復(fù)的標(biāo)準(zhǔn)损同,也是調(diào)用compareTo
方法,如果返回0則是重復(fù)元素(兩個元素相等)堕伪。Java的常見類都已經(jīng)實現(xiàn)了Comparable接口(比如String),String類實現(xiàn)的compareTo
方法:
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
由此我們能看出String會從左到右一個個去比較字符的大小揖庄,如果相同則返回0,只保留第一次加入的元素欠雌。如果大于0則是升序排列,小于0降序排列疙筹。
而且由于compareTo
中需要比較兩種元素的大小值富俄,那么必須保證元素是同一個類禁炒,所以TreeSet中只能存儲同一個類的對象。
2.TreeSet-定制排序:
TreeSet還有一種排序就是定制排序霍比,定制排序時候幕袱,需要關(guān)聯(lián)一個 Comparator對象,由Comparator提供排序邏輯悠瞬。
static void TestTreeSet(){
Comparator com = new Comparator() {
@Override
public int compare(Object o1, Object o2) {
if (o1 instanceof Animal && o2 instanceof Animal){
Animal a1 = (Animal)o1;
Animal a2 = (Animal)o2;
return a1.age - a2.age;
}
return 0;
}
};
TreeSet tree = new TreeSet(com);
tree.add(new Animal(10,"Cat"));
tree.add(new Animal(11,"Dog"));
tree.add(new Animal(15,"Chicken"));
tree.add(new Animal(9,"Duck"));
tree.add(new Animal(7,"Pig"));
tree.add(new Animal(15,"Bear"));
for (Object o: tree) {
Animal animal = (Animal)o;
System.out.println(animal.name + " is " + animal.age + " old");
}
}
Log如下:
Pig is 7 old
Duck is 9 old
Cat is 10 old
Dog is 11 old
Chicken is 15 old