今天來總結(jié)JavaSE部份的集合。首先來從整體來看:
我們主要要學(xué)習(xí)的內(nèi)容:
Collection:
Collection(接口): java.util.Collection
|-- List(子接口) :
|--ArrayList
|--LinkedList
|--Vector
|-- Set(子接口) :
|--AbstracSet(子接口)
|--HashSet
|--LinkedHashSet
|--SortedSet(子接口)
|--TreeSet
|-- Queue(子接口) :
Map:
Map:java.util.Map
Map(接口)
|--HashMap
|--linkedHashMap
|--Hashtable
|--Properties
|--TreeMap
由于Collection是所有集合類的父接口,所以它中的方方法接口和具體實現(xiàn)類都會繼承或?qū)崿F(xiàn),那末先來學(xué)習(xí)Collection:
經(jīng)常使用到的方法:
add(),addAll(),remove(),clear()--> 這兩組方法對照著學(xué)習(xí)記憶。
contains(),isEmpty()
size(), toArray(),iterator()
具體的作用自己去測試下吧。
接下來學(xué)習(xí):
1 List子接口,要明白它的特點是:元素有序且可以重復(fù),怎樣保證它是有序的呢?通過索引來保證的。
所以 List集合里添加了根據(jù)索引來操作集合元素的方法:
get(),set()
indexOf(),lastIndexOf()
subList()
listIterator()
再看看這個結(jié)構(gòu),我們要學(xué)的就是這些內(nèi)容:
|-- List(子接口) :
|--ArrayList
|--LinkedList
|--Vector
1.1 ArrayList:
是List接口的典型實現(xiàn)類,可以把它看成是1個可變長度的數(shù)組
相比于List,也沒有增加新的方法,只是實現(xiàn)了List中的方法
注意:
Arrays.asList() 返回的不是ArrayList,而是1個固定長度的List
1.2 LinkedList:
新增加了鏈表來保護(hù)元素的位置(適用于頻繁的插入和刪除操作)
既然新增了鏈表結(jié)構(gòu),那末它肯定新增了方法:
addFirst(),addLast()
getFirst(),getLast()
removeFirst(),removeLast()
1.3 Vector:
是1個古老的類,它是線程安全的,但是效力低于ArrayList,所以現(xiàn)在很少使用。
操作的是element
2 Set 子接口
|-- Set(子接口) :
|--AbstracSet(子接口)
|--HashSet
|--LinkedHashSet
|--SortedSet(子接口)
|--TreeSet
和List的特點恰恰相反,Set中的元素不能是重復(fù)的,但是可以是無序的。
Set中并沒有提供額外的方法
問題:怎樣來保證兩個元素是不能重復(fù)的?
solution:首先要通過hashCode()方法來比較兩個元素的哈希值是不是相同,如果相同,再通過equals()來判斷他們的內(nèi)容是不是相等,若相等,則重復(fù)。
固然只有具體的實現(xiàn)類才有承接對象的能力,而Set的這個特點對它的實現(xiàn)類都是適用的。
2.1 HashSet:
是Set接口的典型實現(xiàn)類,通過Hash算法來存取數(shù)據(jù),具有很好的查找和存取性能。
2.2 LinkedHashSet:
HashSet的子類,同時增加了鏈表結(jié)構(gòu)來保護(hù)元素的次序,使元素看起來和插入時的順序1致。
由于增加了鏈表結(jié)構(gòu),所以插入的時候效力下降了,而迭代的時候效力提高了
2.3 TreeSet:
是Sorted的子接口,能實現(xiàn)自定義排序
新增的方法:
comparator(),first(),last(),lower(),higer(),subSet(),headSet(),tailSet()
說實話,這么多方法,我只用到了comparator()!!!
自然排序:
TreeSet添加的對象,必須實現(xiàn)Comparable接口,同時實現(xiàn)compareTo()方法
定制排序:
在TreeSet的構(gòu)造器中指定排序方式
①可以通過Comparator的實現(xiàn)類,這個實現(xiàn)類得實現(xiàn)compare()方法
②可以通過匿名內(nèi)部類來直接獲得Comparator接口的實例
③可以在構(gòu)造器中傳入匿名對象。
/*
* 1.請從鍵盤隨機(jī)輸入10個整數(shù)保存到List中,并按倒序、從大到小的順序顯示出來
*
* 2.請把學(xué)生名與考試分?jǐn)?shù)錄入到Map中,并按分?jǐn)?shù)顯示前3名成績學(xué)員的名字。
*/
@Test
public void test3(){
scan = new Scanner(System.in);
List<Integer> list = new ArrayList<Integer>();
for(int i = 0; i < 10; i++){
list.add(scan.nextInt());
}
Collections.sort(list);
Collections.reverse(list);
for(Integer i : list){
System.out.println(i);
}
}
/*
* 1. 定義1個Employee類, 該類包括:private成員變量name,age,birthday,其中 birthday 為 MyDate
* 類的對象; 并為每個屬性定義 getter, setter 方法; 并重寫 toString 方法輸出 name, age, birthday
*
* MyDate類包括: private成員變量month,day,year;并為每個屬性定義 getter, setter 方法;
*
* 創(chuàng)建該類的 5 個對象,并把這些對象放入 TreeSet 集合中
* 分別按以下兩種方式對集合中的元素進(jìn)行排序,并遍歷輸出:
*
* 1). 使Employee 實現(xiàn) Comparable 接口,并按 name 排序 2). 創(chuàng)建 TreeSet 時傳入
* Comparator對象,按生日日期的前后排序。
*
*
*/
@SuppressWarnings("unused")
@Test
public void test2() {
class MyCommparator implements Comparator<Employee> {
@Override
public int compare(Employee o1, Employee o2) {
if (o1.equals(o2))
return 0;
else if (o1.getName().equals(o2.getName()))
return new Integer(o1.getAge()).compareTo(new Integer(o2
.getAge()));
else
return o1.getName().compareTo(o2.getName());
}
}
Comparator<Employee> cpt = new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
if (o1.equals(o2))
return 0;
else if (o1.getName().equals(o2.getName()))
return new Integer(o1.getAge()).compareTo(new Integer(o2
.getAge()));
else
return o1.getName().compareTo(o2.getName());
}
};
TreeSet<Employee> ts = new TreeSet<Employee>(
new Comparator<Employee>() {
@Override
public int compare(Employee o1, Employee o2) {
if (o1.equals(o2))
return 0;
else if (o1.getName().equals(o2.getName()))
return new Integer(o1.getAge())
.compareTo(new Integer(o2.getAge()));
else
return o1.getName().compareTo(o2.getName());
}
});
ts.add(new Employee("zhangsan", 23, new MyDate(12, 12, 1993)));
ts.add(new Employee("zhaoliu", 27, new MyDate(10, 11, 1977)));
ts.add(new Employee("wangwu", 25, new MyDate(22, 1, 1989)));
ts.add(new Employee("zhaoliu", 27, new MyDate(3, 2, 1993)));
ts.add(new Employee("tianqi", 28, new MyDate(2, 4, 1991)));
for (Employee t : ts) {
System.out.println(t);
}
}
// Collection: List:arrayList linkedList / Set: hashSet->linkedHashSet
// treeSet
@Test
public void test1() {
String[] str = new String[5];
for (String s : str) {
s = "atguigu";
System.out.println(s);
}
for (int i = 0; i < str.length; i++) {
System.out.println(str[i]);
}
}
@Test
public void test() {
List<Object> list = new ArrayList<Object>();
list.add(123);
list.add("zhang");
for (Object l : list) {
System.out.println(l);
}
Iterator<Object> itor = list.iterator();
while (itor.hasNext()) {
System.out.println(itor.next());
}
ListIterator<Object> itor1 = list.listIterator();
itor1.add("lisi");
while (itor1.hasNext()) {
System.out.println(itor1.next());
}
}
/*1. 定義1個Employee類,
該類包括:private成員變量name,age,birthday,其中 birthday 為 MyDate 類的對象;
并為每個屬性定義 getter, setter 方法;
并重寫 toString 方法輸出 name, age, birthday
*/
public class Employee{
private String name;
private int age;
private MyDate birthday;
public Employee() {
}
public Employee(String name, int age, MyDate birthday) {
this.name = name;
this.age = age;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public MyDate getBirthday() {
return birthday;
}
public void setBirthday(MyDate birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Employee [name=" + name + ", age=" + age + ", birthday="
+ birthday + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((birthday == null) ? 0 : birthday.hashCode());
return result;
}
// @Override
// public int compareTo(Employee o) {
// if(this == o)
// return 0;
// else if(this.getName().equals(o.getName()))
// return new Integer(this.age).compareTo(new Integer(o.age));
// else
// return this.getName().compareTo(o.getName());
// }
}
//private成員變量month,day,year;并為每個屬性定義 getter, setter 方法;
public class MyDate {
private int month;
private int day;
private int year;
public MyDate() {
}
public MyDate(int month, int day, int year) {
this.month = month;
this.day = day;
this.year = year;
}
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
public int getDay() {
return day;
}
public void setDay(int day) {
this.day = day;
}
public int getYear() {
return year;
}
public void setYear(int year) {
this.year = year;
}
@Override
public String toString() {
return "MyDate [month=" + month + ", day=" + day + ", year=" + year
+ "]";
}
}
3 Queue
是1個古老的接口,是線程安全的,效力低,現(xiàn)在很少使用
到這里Collection集合就先告1段落。
接下來該遍歷了:
4 集合元素的遍歷:
①由于List中有索引,我們可以通過最基本的for循環(huán)來完成,只適用于List集合
②增強for循環(huán),適用于所有集合元素
③迭代器:Iterator
注意:①迭代器本身沒有承接對象的能力,必須通過集合來獲得
②在使用iterator.next()之前,必須使用iterator.hasNext()進(jìn)行判斷,否則會報NoSuchElementException異常
③Enumeration是Iterator的古老版本
Map(接口)
|--HashMap
|--LinkedHashMap
|--Hashtable
|--Properties
|--TreeMap
1 Map
首先來講,Map是和Collection同1級的接口,并列存在,其實不是Collection的子接口。Map用來保存具有映照關(guān)系的數(shù)據(jù):鍵值對(key->value)
key中不允許有重復(fù)的值,可以看成是1個Set集合,判斷是不是重復(fù)和Set相同;而值得話可以重復(fù)
注意理解映照:我昨天的博客“JDBC的進(jìn)化2“中所說的ORM就是1種映照關(guān)系。還記得么?回顧1下:ORM:對象關(guān)系映照,沒1張表對應(yīng)這1個類,每列對應(yīng)1個屬性,每行對應(yīng)1個對象。
方法:
添加、刪除操作:
Object put(Object key,Object value)
Object remove(Object key)
void putAll(Map t)
void clear()
元視圖操作的方法:
Set keySet()
Collection values()
Set entrySet()
元素查詢的操作:
Object get(Object key)
boolean containsKey(Object key)
boolean containsValue(Object value)
int size()
boolean isEmpty()
boolean equals(Object obj)
1.1 HashMap
①允許null鍵,null值,但是不能保證映照的順序
②判斷key值是不是重復(fù),和HashSet相同
1.1.1 LinkedHashMap
類似于HashSet和LinkedHashSet的關(guān)系
1.2 TreeMap
我是這樣理解的,類比于TreeSet,是TreeSet的鍵值對情勢,可以實現(xiàn)自然排序和定制排序
1.3 Hashtable
又是1個古老的類,線程安全,現(xiàn)在很少使用,不允許插入null鍵值,其余和HashMap類似,我們主要用到它的子類Properties
1.3.1 Properties
是Hashtable的子類,它中的key和value都是String類型的,我們常常用它來讀取配置文件信息
Properties pros = new Properties();
pros.load(new FileInputStream("jdbc.properties"));
String user = pros.getProperty("user");
System.out.println(user);
Ok,Map也結(jié)束了。。。
3 工具類(Collections)
可以操作List,Set,Map的1個工具類
它中的方法全為靜態(tài)方法:(學(xué)了這么多了,1提工具類,我們就知道它都是靜態(tài)的方法,擴(kuò)大1下,以后我們自己也能夠創(chuàng)建工具類,來操縱我們具體的實體類,你說是否是這樣的呢?)
方法:
排序操作:
reverse()
shuffle()
sort()
sort(List, Comparator)指定排序方式
swap()
查找和替換:
max(),min()
frequency() 次數(shù)
copy()
replaceAll() 新值替換舊值
到此為止,是否是以為就總結(jié)完了?No,其實還沒有開始總結(jié),上面的僅僅是回顧。我們來總結(jié)。
沒有好的作圖工具(思惟導(dǎo)圖有很大的局限性,可能也是我研究的不夠深),我只能是手畫了,有時候圖形能表達(dá)的東西更多,也更容易理解記憶。
先來這1張整體的
手機(jī)像素有點渣,看不清第1張的,可以看下面的兩張。
畫的不好,但是我認(rèn)為可以表達(dá)意思了。
來,開始的分析:
我是這樣分析的,從整體再到具體(思惟),先縱向再橫向:
1.Collection 和Map,有甚么聯(lián)系和區(qū)分?
聯(lián)系:Collection和Map都是java.util下的集合接口,Collection和Map屬于同1層次。
區(qū)分:Collection中寄存的是1個值(只能可以是任意的對象),而Map中寄存的是鍵值對(固然鍵和值,也只能可以是任意對象)
*再往下走,忘畫1個Queue了。
2.List和Set和Queue有甚么區(qū)分和聯(lián)系
聯(lián)系:都是Collection的子接口。
區(qū)分:List中的元素是有序的,可以重復(fù)的,而Set中的元素是無序的,不可以重復(fù)的;Queue是1個古老的類,是線程安全的,現(xiàn)在很少使用。
*Map和他倆不是1個層次的,沒法進(jìn)行比較
3.ArrayList,LinkedList和Vector的區(qū)分和聯(lián)系
聯(lián)系:都是List的實現(xiàn)類
區(qū)分:LinkedList相比于ArrayList增加了鏈表結(jié)構(gòu)來保護(hù)元素的順序,適用于頻繁的插入和刪除操作,而迭代速度沒有ArrayList快。Vector是1個古老的實現(xiàn)類,是線程安全的,它中的方法和ArrayList類似,但是效力低于ArrayList
*再來比較Set中各個元素
4.HashSet,LinkedHashSet,和TreeSet有甚么區(qū)分和聯(lián)系?
聯(lián)系:HashSet和TreeSet是Set接口的實現(xiàn)類,LinkedHashSet是HashSet的子類。
區(qū)分:HashSet中的對象需要重寫hashCode()和equals()方法,來肯定他們是不是重復(fù),TreeSet中添加的對象需實現(xiàn)Comparable接口,或是在TreeSet構(gòu)造器中指定Comparator接口的實例。相比于HashSet可以插入任意的無序且不重復(fù)的元夙來說,TreeSet有自己的排序方式(自然排序和定制排序)。LinkedHashSet相比于HashSet,增加了鏈表結(jié)構(gòu),插入和刪除數(shù)據(jù)性能要低于HashSet,但是迭代性能要高于HashSet。
*到比較Map了
5.HashMap和TreeMap,和Hashtable的區(qū)分和聯(lián)系?
聯(lián)系:都是Map接口的實現(xiàn)類
區(qū)分:HashMap中的鍵都是Set集合,但是可以將HashMap中的鍵認(rèn)為成是HashSet,而TreeMap中的鍵是TreeSet,TreeMap可以按TreeSet中的排序方式來排序。相比于HashMap,Hashtable是1個古老的實現(xiàn)類,它是線程安全的,它不允許插入null鍵和null值,而HashMap則允許。
最后就是整體的橫向?qū)φ眨?
各個實現(xiàn)類的適用處景和效力對照:
首先進(jìn)行分類:將List,Set和Map分開,由于寄存的內(nèi)容不相同。
1.List內(nèi)部比較:
ArrayList: 有索引,遍歷相對來講較快,效力高;插入和刪除時,需要移動很多數(shù)據(jù),所以較慢,效力低。
LinkedList:有索引,有鏈表,遍歷快,插入和刪除效力高,但是增加鏈表后,需要保護(hù)鏈表也需要1定的資源。
2.Set內(nèi)部比較
HashSet:無序,插入快,刪除快,遍歷,非常慢。
TreeSet:插入和刪除,和遍歷效力不肯定,由于不知道排序的算法有多么復(fù)雜,但是我認(rèn)為,整體來講它的效力不會高。
LinkedHashSet:插入和刪除效力要低于HashSet,由于增加了鏈表結(jié)構(gòu),但是迭代速度增加了很多。算是1種平衡吧。用來平衡效力
3.List和Set做比較
List:有索引,相對來講遍歷較快,而插入,刪除較慢
Set:無索引,插入和刪除非???,遍歷非常慢。
這幾個效力的比較是我自己根據(jù)他們的理解來判斷的,沒有學(xué)過數(shù)據(jù)結(jié)構(gòu)和算法,等我學(xué)完后,就可以明確的給出1個效力了,得斟酌它們的數(shù)據(jù)結(jié)構(gòu)和算法復(fù)雜度。有興趣的朋友可以和我1起研究。
4.總結(jié)各適用于甚么場景:
上1張圖吧(又是自己畫的?。?
5.Map就不做說明了。對照上面的Set,相信你自己也能明白了。
HashMap
TreeMap
LinkedHashMap:
差點忘了,還有1個要補充的:
ListIterator 和Iterator的區(qū)分
ListIterator是Iterator的子接口,只適用于List,它可以在遍歷的時候增加,設(shè)置,移除值,同時它可以逆向遍歷。(逆向遍歷我沒明白,必須將它的指針移到最后,你才可以逆向遍歷,相當(dāng)于,你先正向遍歷后,將指針移到最后,才能逆向遍歷)
@Test
public void test5(){
// when the element is "def", insert "bbb" or modify to "bbbb", and remove "def";
List<String> list = new ArrayList<String>();
list.add("abc");
list.add("def");
list.add("ghi");
ListIterator<String> li = list.listIterator();
while(li.hasNext()){
String str = li.next();
if(str.equals("def")){
// li.add("bbb");
li.set("aaaa");
li.remove();
}
}
System.out.println(list);
}
Ok,總算是就集合總結(jié)完了,有耐心看完的朋友,相信你會收獲不小。固然,我這總結(jié)的可能也會有很多的漏洞,歡迎大家指導(dǎo)。睡覺了。