集合:容器,用一個對象管理多個對象;
集合VS 數組
數組:不能自動增長;只能存放同類型的元素
集合:能自動擴容;部分集合允許存放不同類型的元素;
Collection:父接口;
Set:接口 ---一個實現類: HashSet
List:接口---三個實現類: LinkedList,Vector,ArrayList
SortedSet:接口---實現類:TreeSet
List:有序列表,允許存放重復的元素;
實現類:
ArrayList:數組實現,查詢快,增刪慢,線程不安全,輕量級;下標也是從0開始;
LinkedList:鏈表實現,增刪快,查詢慢
Vector:數組實現,線程安全,重量級
Set: 無序集合,不允許存放重復的元素;
實現類
HashSet:equals返回true,hashCode返回相同的整數;哈希表;
SortedSet:對Set排序
實現類
TreeSet:二叉樹實現的;
Iterator:接口,迭代器;java.util;hasNext();next();remove();
Iterable:可迭代的,訪問的 ;java.lang;實現了可迭代的接口就可以用迭代的方式訪問;
只需實現 iterator();方法即可;Iterator iterator();
模擬:
class ArrayList{
Iterator iterator(){
return new Iterator(){
public boolean hasNext(){}
public Object next(){}
...
};
}
}
三種循環的訪問方式:
for(int i=0;i<list.size();i++){
System.out.println(list.get(i));
}
Iterator it=list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
for--each 循環:
for(Object obj:list){
System.out.println(obj);
}
只有實現了Iterable接口的才能用第三種;能用第二種的也一定能用第三種;
數組:優:訪問快,操作效率高,
缺:插入刪除效率低,長度不能變;
鏈表:跟數組相反
ArrayList:自動擴容,是數組照搬過來的;
========
HashSet:
========
構造方法:
HashSet(int initialCapacity)
通過Hash散列存儲;希望元素均勻的分布在存儲空間內;
Hash散列擴容并不是所有的空間都放滿才申請新的空間;一般是75%的容量后就去擴容;
可以自己指定;10%就去擴容,保證了效率,浪費了空間;
Set放進去的順序和取出來的順序不一致;不允許有重復的元素;覆蓋hashcode()方法;
Iterator it=set.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
for(Object o:set){
System.out.println(o);
}
=================
ArrayList/LinkedList
=================
1、 用List實現一個棧;
2、 set是怎么實現的?
set.add("hello"); hash函數運算,()%16 -----0~15之間的值;
obj.hashcode();//Object對象的
HashSet,放到Hash散列里,有輸入: 得到哈希碼,obj.hashcode(),對16求余,有輸出,放到相應的位置;
如果發生沖突,先判斷要加進去的對象的equals(已經放進去的對象);是否相等;
如果obj1.equals(obj2)=true;那么舍棄obj2;
否則,調用沖突處理機制,將obj2放到另外一個位置;
兩個Student對象的equals 相等;但是哈希碼不相等,所以沒有覆蓋;
hs.add(obj);--->obj.hashcode();得到哈希碼--->做運算得到下標--->看是否沖突:如果不沖突直接加
----> 如果沖突,調用equals方法,如果返回真,那么不加obj,否則找某個空位加進來;
Object里的hashcode()方法默認返回的是兩個對象的地址;
String 類覆蓋了hashcode()方法,人為制造沖突,它認為相同的串返回相同的hashcode;
只有要放到hash散列時才用到hashcode方法;
放到set里能保證對象不重復,自定義類要 覆蓋hashcode方法;
覆蓋hashcode方法原則:
1)、一定要讓那些我們認為相同的對象返回相同的hashcode值;equals()相等;
public int hashcode(){ return 1; } //能達到要求,意味著把取舍權利完全交給equals;
能達到效果,但是效率太低;
2)、考慮效率,盡量讓那些我們認為不相同的對象返回不同的hashcode值;
public int hashcode(){ return this.name.hashcode()+this.age; }
//只有name和age都相等才會返回相同的哈希碼;避免了不必要的沖突;
減少了通過equals比較的次數,提高了效率;
3)、盡量的讓對象的hashcode值散列開;即隨機分布,均勻分布;
this.age+this.id;//并沒有散列開;21~140
用屬性(如果是整數直接用,否則取屬性的hashcode())做 ^ 異或;相同為0,不同為1;比21~140范圍要大;
toString方法默認返回的是 類名@地址 (如果覆蓋了hashcode方法,那么輸出的是hashcode方法的返回值)
day07.Student@1;
注:只覆蓋hashcode不覆蓋equals是無意義的;發生沖突后,
比equals時比的仍然是地址;hashcode是為hash散列服務的;
只覆蓋equals我們要比較的是兩個對象是否相等;并不放到hash散列中去;
===============
SortedSet:TreeSet
===============
有序:加載的順序跟放的順序一致
無序:加載的順序跟放的順序不一致
排好序:按照集合中值的大小排列;不需要手工寫排序的代碼;
原則:
1) 往TreeSet:中放的對象必須是同類型的;
2) 能夠比較大小;定義比較規則;TreeSet 自己有比較的方法;
java.lang.Comparable //可比較的;
int compareTo(T o) //小的話返回負整數,相等返回0;大的話返回正整數;
public int compareTo(Object o){
Student s=(Student)o;
return this.age-s.age;
}
TreeSet中不允許出現CompareTo結果為0的兩個對象;
String 覆蓋了CompareTo方法,是 按字典順序排列的;
Comparetor :java.util包下的;
java.lang包:
Iterable:可迭代的
Comparable:可比較的 compareTo()方法怎么覆蓋
java.util包:
Iterator:迭代器
Comparetor:比較器
java.util包里的;
public class MyComparator implements Comparator{
public int compare(Object o1,Object o2){
Student s1=(Student)o1;
Student s2=(Student)o2;
return s2.getAge()-s1.getAge();//按從大到小排列;
}
}
在構造TreeSet時構造進去:
TreeSet ts=new TreeSet(new MyComparator());
如果在TreeSet中構造了比較器就用比較器的比較規則;
如果沒有構造比較器就直接用自定義類中的CompareTo的比較規則;
=====
Map:
=====
HashMap:鍵值對,key不能重復,但是value可以重復;key的實現就是HashSet;value對應著放;
HashSet 的后臺有一個HashMap;初始化后臺容量;只不過生成一個HashSet的話,系統
只提供key的訪問;
如果有兩個Key重復,那么會覆蓋之前的;
HashTable:線程安全的
Properties:java.util.Properties; key和value都是String類型,用來讀配置文件;
兩者區別:HashMap線程不安全的,允許null作為key或value;
HashTable線程安全的,不允許null作為key或value;
TreeMap: 對key排好序的Map; key 就是TreeSet, value對應每個key;
key要實現Comparable接口或TreeMap有自己的構造器;
HashSet:remove(Object o)的原則看這個對象O的Hashcode和equals是否相等,并不是看是不是一個對象;
定義一個Map; key是課程名稱,value是Integer表示選課人數;
map.put(cou,map.get(cou)+new Integer(1));
(int)(Math.random()*cou.length);從0到要選的課程數減-1
本章學習方向:熟練使用API,記住常用的幾個容器及其特點
===================================
擴展:容器中裝容器
每個Collecton 都有一個addAll()方法,可以把一個集合完全裝載到另外一個集合里面:例如:
Set set=new Set();
List ls=new List();
Ls.addAll(set);//把Set裝載在list里面。
====================================
面試經驗(知識點):
java.util.stack(stack即為堆棧)的父類為Vector。可是stack的父類是最不應該為Vector的。因為Vector的底層是數組,且Vector有get方法(意味著它可能訪問到并不屬于最后一個位置元素的其他元素,很不安全)。
對于堆棧和隊列只能用push類和get類。
Stack類以后不要輕易使用。
!!!實現堆棧一定要用LinkedList。
(在JAVA1.5中,collection有queue來實現隊列。)
====================================
注:HashMap底層也是用數組,HashSet底層實際上也是HashMap,HashSet類中有HashMap屬性(我們如何在API中查屬性)。HashSet實際上為(key.null)類型的HashMap。有key值而沒有value值。
正因為以上的原因,TreeSet和TreeMap的實現也有些類似的關系。
注意:TreeSet和TreeMap非常的消耗時間,因此很少使用。
我們應該熟悉各種實現類的選擇——非常體現你的功底。
HashSet VS TreeSet:HashSet非常的消耗空間,TreeSet因為有排序功能,因此資源消耗非常的高,我們應該盡量少使用,而且最好不要重復使用。
基于以上原因,我們盡可能的運用HashSet而不用TreeSet,除非必須排序。
同理:HashMap VS TreeMap:一般使用HashMap,排序的時候使用TreeMap。
HashMap VS Hashtable(注意在這里table的第一個字母小寫)之間的區別有些類似于ArrayList和Vector,Hashtable是重量級的組件,在考慮并發的情況,對安全性要求比較高的時候使用。
Map的運用非常的多。
==========================================
組合復用原則:
*白盒復用和黑盒復用
1.白盒復用:又叫繼承復用,從某種程度上說白盒復用破壞了封裝。
例:class Zhangsw{
public void teachCpp(){
System.out.println("Teach Cpp");
}
public void chimogu(){
}
}
class Xiaozr extends Zhangsw{
}
2.黑盒復用:又叫組合復用。
例:class Zhangsw{
public void teachCpp(){
System.out.println("Teach Cpp");
}
public void chimogu(){
}
}
class Xiaozr {
private Zhangsw zhangsw = new Zhangsw();
public void teachCpp(){
zhangsw.teachCpp();
}
}
3.原則:組合復用取代繼承復用。
柴油發電機
發電機
柴油機
柴油發電機
13636374743(上海)
13291526067(嘉興)