一.框架概述
在開發過程中,java提供的集合框架(Collection)技術給我們提供了很多的便利,他封裝了很多的數據結構(如數組,鏈表,堆,棧等),並未這些數據結構提供了很多的成員方法供我們很方便的去使用這些數據結構。
java中的框架技術,我們先看一下他的結構:
Collection
|-List
|-ArrayList
|-LinkedList
|-... ...
|-Set
|-HashSet
|-TreeSet
|-... ...
Map
|-HashTable
|-HashMap
|-TessMap
|-... ...
以上結構中列出的是我們需要理解掌握的具體的集合類,java中的集合框架,其實就是對存放數據的容器進行的封裝,我們需要學會的是如何對這些容器進行操作,來實現我們需要的增刪改查。
二.List
首先將講一下List,他的存儲方式是有序的,所謂有序就是,以什麼順序存進去,就會以什麼順序遍歷獲得,允許存放相同的元素,實現他的兩個重要的子類是ArrayList跟LinkedList。
ArrayList與LinkedList的區別:
ArrayList:數據原型爲數組,帶有索引,用於數據獲取比較方便,對於插入,刪除數據的操作比較慢。線程不同步。
LinkedList:數據原型爲鏈表,對於數據的插入,刪除比較高效,數據的檢索獲取就相對低效一點。線程不同步。
他們的的增刪改查操作比較簡單,無非就是一些add,remove,set等操作,查閱api即可,主要看一下遍歷的問題。在集合中,java提供了Iterator(迭代器)來遍歷集合:
List l = new LinkedList();
l.add("qwer");
...//添加操作
Iterator iterator = l.iterator();
while(iterator.hasNext()){
sop(iterator.next());
}
由於Iterator值提供了hasNext(), next(), remove()三個方法,功能比較簡單,無法實現逆向遍歷的操作,在LinkedList中提供了listIterator(int index),返回一個ListIterator接口對象,在java源碼中我們可以發現LickedList中有一個實現了ListIterator的內部類,它實現了ListIterator裏面的方法,因此,返回的ListIterator對象可以實現逆向遍歷的操作,詳細操作參閱API。
三.Set
Set的存儲方式是無序的,元素不可重複的。我們以a->b->c->d的順序想Set中存儲數據時,我們不能夠保證以a->b->c->d的順序取出,Set的底層是有Map實現的。Set的相關操作也是參閱API,比較簡單,遍歷方式也是與ArrayList一樣的,獲取一個Iterator對象進行遍歷,這邊我們主要需要了解的是他們是根據什麼來判斷存儲的先後順序的。
HashSet:他的底層數據結構是哈希表,線程不同步。
我們看一下下面這段代碼:
public class Demo {
public static void main(String[] args) {
HashSet<Student> s = new HashSet<Student>();
s.add(new Student("zhangsan", 22));
s.add(new Student("zhangsan", 21));
s.add(new Student("lisi", 21));
sop(s);
}
private static void sop(Object obj){
System.out.println(obj);
}
}
class Student {
public String name;
public int age;
public Student(String name, int age){
this.name = name;
this.age = age;
}
public int hashCode(){
System.out.println(this.name + " -----> hashCode");
return name.hashCode();
}
public boolean equals(Object obj){
if(!(obj instanceof Student))
return false;
Student s = (Student)obj;
System.out.println(this.name + " +++ equals +++ " + s.name);
return (this.age == s.age);
}
public String toString(){
return this.name + ":" + this.age;
}
}
然後我們看一下他的運行結果
zhangsan -----> hashCode
zhangsan -----> hashCode
zhangsan +++ equals +++ zhangsan
lisi -----> hashCode
[lisi:21, zhangsan:21, zhangsan:22]
我們不難發現,在向HashSet中添加元素的時候,首先會調用對象的hashCode方法比較哈希值,如果哈希值相等,還會調用equals方法進行進一步的比較。所以,他是通過hashCode與equals兩個方法去實現插入元素的唯一性的。
TreeSet:他的底層數據結構是二叉樹,線程不同步,他實現插入唯一性有兩種方法:
(1)插入對象實現Comparable接口,實現裏面的compareTo方法
只需要將上述的Student做一下修改即可
class Student implements Comparable<Student>{
/*
* ... ...
*/
@Override
public int compareTo(Student s) {
// TODO Auto-generated method stub
int i = this.name.compareTo(s.name);
if(i == 0)
return Integer.valueOf(this.age).compareTo(Integer.valueOf(s.age));
return i;
}
(2)新建一個類,實現Comparator接口,實現裏面的compare方法,然後將該類作爲參數傳進TreeSet的構造函數
public class SplitDemo {
public static void main(String[] args) {
TreeSet<Student> s = new TreeSet<Student>(new stuCompare());
s.add(new Student("zhangsan", 21));
s.add(new Student("zhangsan", 22));
s.add(new Student("lisi", 21));
sop(s);
}
private static void sop(Object obj){
System.out.println(obj);
}
}
class stuCompare implements Comparator<Student>{
@Override
public int compare(Student stu1, Student stu2) {
System.out.println(stu1.name + " ===> " + stu2.name);
int i = stu1.name.compareTo(stu2.name);
if(i == 0)
return Integer.valueOf(stu1.age).compareTo(Integer.valueOf(stu2.age));
return i;
}
}
四.Map
Map主要是以鍵值對(Key-Value)的形式進行存儲的,他的存儲也是無序的,不可重複的。Map接口中並沒有提供Iterator,所以,他的遍歷不是以Iterator實現的,Map中實現遍歷有以下兩種方式:
(1)keSet方法
Map<String, String> m = new HashMap<String, String>();
m.put("1", "hello1");
m.put("2", "hello2");
m.put("3", "hello3");
m.put("4", "hello4");
m.put("5", "hello5");
Set<String> set = m.keySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
String str = (String)iterator.next();
sop(str + ":" + m.get(str));
}
(2)entrySet方法
Set<Map.Entry<String,String>> set = m.entrySet();
Iterator iterator = set.iterator();
while(iterator.hasNext()){
Map.Entry<String, String> entry = (Map.Entry<String, String>)iterator.next();
sop(entry.getKey() + ":" + entry.getValue());
}
HashTable:根據哈希值存儲,允許存儲null鍵null值,支持線程同步,存儲無序
HashMap:根據哈希值存儲,不允許存儲null鍵null值對象,不支持線程同步,存儲無序
TreeMap:存儲有序,其有序原理與TreeSet一樣,在構造函數中將實現Comparator的類對象傳入,此處不再做過多介紹。