JAVA之容器類簡介

一、容器簡介

容器是一個將多個元素組合到一個單元的對象,是代表一組對象的對象,容器中的對象成爲它的元素。容器適用於處理各種類型的對象的聚集,例如存儲、獲取、操作聚合數據,以及聚合數據的通信。容器只保存Object型的引用,這是所有類的基類,因此容器可以保存任何類型的對象。

二、容器接口的分類

根據容器所包含的對象的不同可以將容器接口分爲Collection和Map兩大類,實現Collection接口的容器實現是一個包含孤立元素的對象集合,而實現Map接口的容器實現是一個包含成對元素的對象集合。

1)、Collection接口代表一組對象,這些對象稱爲它的元素。Collection是容器繼承樹中的頂層接口,作爲接口它定義了15個方法,但沒有提供具體的實現。

Collection接口如下:

public interfaceCollection<E>extends Iterable<E>{
//接口的基本操作
int size();//返回容器中元素的數目
boolean isEmpty();//容器中沒有元素的時候返回true
boolean contains(Objectelement); //如果容器中已經持有參數則返回true
boolean add(Eelements);//確保容器持有此參數,如果沒有將此參數添加進容器則返回false
boolean remove(Objectelement);//如果參數在容器中,則移除此參數的一個實例,如果做了移除動作則返回true
Iterator<E>iterator(); //返回一個Iterator,可以用來遍歷容器中的元素
boolean equals(Objectelement) //比較容器與給定對象是否相等,如相等則返回ture,此方法重載了Object的equals()方法
int hashCode();//返回對象的hash碼
boolean containsAll(Collection<?>c); //如果容器持有參數中的所有元素則返回true
boolean addAll(Collection<?extends E> c); //添加參數中的所有元素,只要添加了任意元素就返回true
boolean removeAll(Collection<?> c);//移除參數中的所有元素,只要有移除動作發生就返回true
boolean retainAll(Collection<?> c);//只保留參數中的元素,只要Collection發生了改變就返回true
void clear();//移除容器中的所有元素
Object []toArray (); //返回一個數組,包含容器中的所有元素
<T> T[]toArray(T[]a);//返回一個數組,包含容器中的所有的元素,其類型與數組a的類型相同,而不是單純的Object(你必須對此數組做類型轉換)

}

Collection接口方法使用示例:
import java.util.*;
class ContainerDemo{
@SuppressWarnings("unchecked")//解決編譯時報錯:使用了未經檢查或不安全的操作,注意:要了解詳細信息,請使用 -Xlint:unchecked重新編譯
public staticvoid main(String []args){
List c1 =new ArrayList(25);//25是初始容量的參數
c1.add(newString("One"));
c1.add(newString("Two"));
String s="Three";
c1.add(s);
for(inti=0;i<c1.size();i++)
System.out.println(c1.get(i));

Object[] array=c1.toArray();//返回一個數組包含容器中所有的元素
String[] str=(String[])c1.toArray(newString[0]);//返回一個數組,包含容器中所有的元素,使用強制類型轉換使返回的值爲String型
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(str));

Collection c2 =new ArrayList(2);
c2.add(newString("Four"));
c2.add(newString("Five"));
c1.addAll(c2);
for(inti=0;i<c1.size();i++)
System.out.println(c1.get(i));

Collection c3 =new ArrayList(2);
c3.add(newString("Two"));
c3.add(newString("Five"));
c1.removeAll(c3);
for(inti=0;i<c1.size();i++)
System.out.println(c1.get(i));
c1.retainAll(c2);
for(inti=0;i<c1.size();i++)
System.out.println(c1.get(i));

}
}

2)Map接口定義與應用
Map是一個將鍵映射到值的對象,映射不能包含重複的鍵,即每個鍵最多可以映射到一個值。
Map接口如下:
public interfaceMap<K,V>{
int size();// 返回容器中元素的數目
boolean isEmpty();// 容器中沒有元素的時候返回true
boolean containsKey(Objectkey); //如果容器中已經持有參數鍵值則返回true
boolean containsValue(Objectvalue);//如果容器已經持有參數值則返回true
V get(Objectkey);//取得鍵值所對應的值
V put(Vkey,K value);//向容器中添加一個鍵值對
V remove(Objectkey);//如果鍵值參數在容器中,則移除此參數鍵值對應的鍵值對實例
void putAll(Mapt);//添加參數中的所有的鍵值對實例
void clear();
public Set<K>keySet();//返回Map中包含的鍵值Set。返回的是一個實現Set接口的對象,對該對象的操作就是對映射的操作。這樣的集合稱爲視圖
public Collection<V>values();//返回Map中所有的值的Collection
public Set<Map.Entry<K,V>>entrySet(); //返回Map中包含的鍵值對的Set
public interfaceEntry{
K getKey();
V getValue();
V setValue(Vvalue)
} //Map接口提供的一個小小的嵌套接口
}

3) 集合容器Set
Set是不包含重複元素的Collection。Set對於包含非重複,且無排序要求的數據結構非常合適。Set接口如下:
public interfaceSet<E> extends Collection<E>{
int size();
boolean isEmpty();
boolean contains(Objectelement);
boolean add(Eelements);
boolean remove(Objectelement);
Iterator<E>iterator();
boolean equals(Objectelement);
int hashCode();
boolean containsAll(Collection<?>c);
boolean addAll(Collection<?extend E> c);
boolean removeAll(Collection<?>c);
boolean retainAll(Collection<?>c);
void clear();
Object[] toArray();
<T> T[]toArray(t[]a);
}
Set接口元素非重複性演示
import java.util.*;
public classFreq{
public staticvoid main(Stringargs[]){
test(newHashSet<String>());
test(newTreeSet<String>());
test(newLinkedHashSet<String>());
}
static voidfill(Set<String>s){
s.addAll(Arrays.asList(
"one two three four five six seven".split(" ")
));
}

public staticvoid test(Set<String>s){
System.out.println(
s.getClass().getName().replaceAll("\\w+\\.","")
);
fill(s);fill(s);fill(s);
System.out.println(s);
s.addAll(s);
s.add("one");
s.add("one");
s.add("one");
System.out.println(s);
System.out.println("s.contains(\"one\"):"+s.contains("one"));
}
}
結果是:


SortedSet接口的附加功能:
Comparator comparator() //返回當前Set使用的Comparator,或者返回null,表示自然方式排序
Object first() //返回容器中的第一個元素
Object last() //返回容器中的最末一個元素
SortedSet subSet(fromElement,toElement) //生成此Set的子集,範圍從fromElement(包含)到toElement(不包含)
SortedSet headSet(toElement)//生成此set的子集,由小於toElement的元素組成
SorttedSet tailSet(fromElement)//生成此set的子集,由大於或等於fromElement的元素組成

sortedSet接口附加功能演示
import java.util.*;
public classFreq{
@SuppressWarnings("unchecked")
public staticvoid main(Stringargs[]){
SortedSet sortedSet =new TreeSet(Arrays.asList("one two three four five six seven eigth".split(" ")));
System.out.println(sortedSet);
Object low =sortedSet.first();
Object high=sortedSet.last();
System.out.println(low);
System.out.println(high);
Iterator it=sortedSet.iterator();
for(inti=0;i<=6;i++){
if(i==3) low=it.next();
if(i==6) high=it.next();
else it.next();
}
System.out.println(low);
System.out.println(high);
System.out.println(sortedSet.subSet(low,high));
System.out.println(sortedSet.headSet(high));
System.out.println(sortedSet.tailSet(low));
}
}

4)Set實現
Set實現分爲通用實現和專用實現。通用實現包括HashSet、TreeSet和LinkedSet;專用實現包括EnumSet和CopyonWriteArraySet.
(1)HashSet
HashSet比TreeSet要快的多。但是HashSet不提供排序保障。HashSet中迭代時間與元素數量和存儲桶數量的總和成正比。系統默認的HashSet
的初始容量是16。我們可以使用int構造器指定初始容量,下面一行代碼就是分配一個初始容量爲64的HashSet:
Set<String> s = new HashSet<String>(64);
一般設置的HashSet的初始容量應該是你預期集合會增長到的尺寸的兩倍。HashSet的底層是由HashMap構建的。
對於HashSet,我們要爲存放在散列表的各個對象定義hashCode()和equals()
HashSet的應用實例:
import java.util.*;
public classFreq{
@SuppressWarnings("unchecked")
public staticvoid main(Stringargs[]){
HashSet hs =new HashSet();
hs.add(newStudent(1,"zhangsan"));
hs.add(newStudent(2,"lisi"));
hs.add(newStudent(3,"wangwu"));
hs.add(newStudent(1,"zhangsan"));
Iterator it =hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}

class Student{
int num;
String name;
Student(intnum,String name)
{
this.num=num;
this.name=name;
}

public StringtoString(){
return "num:"+num+"name:"+name;
}

public inthashCode(){ //重載了hashCode()方法
return num*name.hashCode();
}
public booleanequals(Objecto){ //重載了equals()方法
Student s = (Student)o;
return num==s.num&&name.equals(s.name);
}
}

結果是:


(2)TreeSet
TreeSet是SortedSet的唯一實現形式,採用紅黑樹的數據結構進行排序元素,當需要按值排序迭代時,那麼需要使用TreeSet。TreeSet由
TreeMap實例支持,TreeSet保證排序後的Set按照升序排列元素,根據使用的構造方法的不同,可能會按照元素的自然順序進行排序,或按照在
創建Set時所提供的比較器進行排序,這個Set是一個有序集合,默認是按照自然順序進行排序,意味着TreeSet中元素要實現Comparable接口
所以我們可以在構造TreeSet對象時,傳遞實現Comparator接口的比較器對象
範例:
import java.util.*;
public classFreq{
@SuppressWarnings("unchecked")
public staticvoid main(Stringargs[]){
TreeSet ts =new TreeSet();
ts.add(newStudent(2,"zhangsan"));
ts.add(newStudent(3,"lisi"));
ts.add(newStudent(1,"wangwu"));
ts.add(newStudent(4,"mali"));
Iterator it =ts.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}

class Student implements Comparable {
int num;
String name;
Student(intnum,String name)
{
this.num=num;
this.name=name;
}

static class compareToStudent implements Comparator{
public intcompare(Objecto1,Object o2){
Student s1=(Student) o1;
Student s2=(Student) o2;
int rulst=s1.num>s2.num?1:(s1.num==s2.num?0:-1);
if(rulst==0){
rulst=s1.name.compareTo(s2.name);
}
return rulst;
}
}

public intcompareTo(Objecto){
int result;
Student s=(Student)o;
result = num>s.num?1:(num==s.num?0:-1);
if(result == 0){
result = name.compareTo(s.name);
}
return result;
}
public StringtoString(){
return Integer.toString(num)+":"+name;
}
}

結果是:


(3)LinkedHashSet
LinkedHashSet在某種程度上介於HashSet和TreeSet之間,此鏈接列表定義了迭代順序,即按照將元素插入到集合中的順序進行迭代,而運行速度和
HashSet一樣快。
(4)EnumSet
EnumSet是用於枚舉類型的高性能Set實現。枚舉集的所有成員都必須是相同的枚舉類型。在內部,它表示爲向量,典型情況下是單一的long值。枚舉
集支持對枚舉類型範圍的迭代
(5)CopyOnWriteArraySet
CopyOnWriteArraySet是通過複製數組支持的實現。所有導致變化的操作(比如add、set和remove)都通過製作數組的新副本而實現,從不需要加鎖,即
使迭代也可以與元素插入和刪除安全的併發進行。這個實現只適用於很少修改但是頻繁迭代的集。

5)列表容器List
List是一個有序的Collection接口,它有時被稱爲序列。次序是List最重要的特點。它確保維護元素特定的順序。List非常適合實現有順序要求
的數據結構,例如堆棧和隊列。
List接口如下:
public interface List<E> extends Collection<E>{
E get(int index);//取特定元素。返回給定地址index的元素
E set(int index);//用給定的對象替換List中指定位置的元素,並且返回被替換的元素
boolean add(E elements);//插入一個給定的對象
boolean add(int index, E elements);//在指定位置插入一個給定的對象,而原先在此位置的元素,以及其後續的元素依次右移
E remove(int index);//在List中刪除指定位置index的元素,並將其後續的元素依次左移,返回被刪除的元素
boolean addAll(int index ,Collection<? extend E> c);//將給定容器c中的所有的元素加入到本集合中index位置,而原先位置及其後面的元素依次往後移動
int indexOf(object o);//查找。返回對象在List中第一次出現的索引值,如果對象不是List的一個元素則返回-1
int LastIndexOf(object o);//返回對象在List中最後一次出現的索引值,如果對象不是List的一個元素則返回-1
ListIterator<E> ListIterator();//迭代器。按照一定順序返回List中的元素的一個列表迭代器
ListIterator<E> ListIterator(int index);//按照一定順序返回List中的元素的一個列表迭代器,從給定的位置index開始
List<E> subList(int from,int to);//範圍視圖。返回該List中從fromindex到toindex指定元素組成的一個List
}

List接口方法演示
package LianXi;
import java.util.*;


public class ListDemo {
public static List fill(List fill_a){
fill_a.add("a");
fill_a.add("b");
fill_a.add("c");
return fill_a;
}

private static boolean b;
private static Object o;
private static int i;
private static Iterator it;
private static ListIterator lit;
public static void basicTest(List a){
a.add(0,"x");
a.add("8");
System.out.println("初始List A爲:"+a);
a.addAll(fill(new ArrayList()));//追加新的List
System.out.println("追加新的List後,List A爲:"+a);
b=a.contains("c");
if(b){
System.out.println("元素c包含在List A中");
    }
else{
System.out.println("元素c沒有包含在List A中");
}
//判斷子List<a,b,c>是否在ListA中
b=a.containsAll(fill(new ArrayList()));
if(b){
System.out.println("List<a,b,c>包含在ListA中");
}
else{
System.out.println("List<a,b,c>沒有包含在ListA中");
}
o= a.get(1);//得到位置1處的元素
System.out.println("位置1元素爲:"+o);
 i=a.indexOf("c");//指定元素c第一次出現的位置
 System.out.println("元素c第一次出現的位置爲:"+i);
b= a.isEmpty();
if(b){
System.out.println("List A是空的");
}
else{
System.out.println("List A不是空的");
}
a.remove(1);
System.out.println("位置1元素被刪除後,List A爲:"+a);
a.remove("c");//刪除第一個“c”元素
a.set(1, "y");//將位置1的元素替換爲y
System.out.println("位置1的元素被替換爲y,List A爲:"+a);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
        basicTest(new LinkedList());
}
}

運行結果:
初始List A爲:[x, 8]
追加新的List後,List A爲:[x, 8, a, b, c]
元素c包含在List A中
List<a,b,c>包含在ListA中
位置1元素爲:8
元素c第一次出現的位置爲:4
List A不是空的
位置1元素被刪除後,List A爲:[x, a, b, c]
位置1的元素被替換爲y,List A爲:[x, y, b]

6)List實現
List有兩個通用的List實現:ArraList和LinkedList.一個專用的List實現時CopyOnWriteArrayList
(1)ArrayList
ArrayList是由數組實現的List,是最常用的List實現。它提供常量時間的位置訪問,而且速度很快,它不必爲List中的每個元素分配一個節點對象。
而且在同時移動多個元素時它可以利用System.arrayCopy,可以把ArrayList看做沒有同步開銷的Vector。但是向List中間插入和移動元素的速度
很慢,ListIterator只應該用來由後向前遍歷ArrayList,而不是用來插入和移除元素,因爲那比LinkedList開銷要大很多。
ArrayList有一個調優參數--初始容量,它是指在ArrayList被迫增長之前其可以容納的元素數量。
(2)LinkedList
如果我們採用的數據結構經常需要將元素添加到List開頭,或者迭代List以便從其內部刪除元素,那麼LinkedList是首要考慮的選擇因爲這些
操作在LinkedList上需要常量時間,而在ArrayList中需要線性時間。而位置操作在LinkedList中需要線性時間,在ArrayList上需要常量時間
,LinkedList沒有用於調優的參數,但它有7個可選方法,分別是Clone、AddFirst、removeFirst、addLast、getLast和removeLast
(3)CopyOnWriteArrayList
CopyOnWriteArrayList是通過複製數組支持的List,這個實現在性質上和CopyOnWriteArraySet類似,不必進行同步,並且確保迭代器不拋出
ConcurrentModificationexception異常。這個實現非常適合這樣的情況:遍歷很頻繁,而且可能很消耗時間。

(4)ArrayList、LinkedList和CopyOnWriteArrayList三者的區別
ArrayList的底層是由數組實現的,LinkedList的底層是由鏈表實現的。所以,對於隨機訪問get和set,ArrayList要優於LinkedList因爲
LinkedList要移動指針。對於新增和刪除add和remove,LinkedList要優於ArrayList,因爲ArrayList要移動數據
ArrayList和LinkedList都是線程不安全的,CopyOnWrteArrayList是線程安全的


7)使用List實現堆棧和隊列
(1)堆棧
堆棧(stack)又名疊堆,是一種簡單的數據結構,它是用後進先出的方式來描述數據的存取方式。
堆棧的定義:限定只能在固定一端進行插入和刪除操作的線性表,允許進行插入和刪除操作的一端稱爲棧頂,另一端稱爲棧底。向棧中插入數據的操作
稱爲壓入(Push),從棧中刪除數據稱爲彈出(Pop).
LinkedList實現堆棧:
package LianXi;
import java.util.LinkedList;
public class ListDemo {
private LinkedList list = new LinkedList();
public void push(Object v){
list.addFirst(v);
}
public Object top(){ //壓棧
return list.getFirst();
}
public Object pop(){ //彈棧
return list.removeFirst();
}
public static void main(String[] args) {
ListDemo stack  = new ListDemo();
for (int i=0;i<10;i++){
stack.push(new Integer(i));
//打印當前的棧頂
System.out.print(stack.top()+" ");
}
System.out.println();
System.out.print(stack.top()+" ");
//彈棧,並打印當前彈出的元素
System.out.print(stack.pop()+" ");
System.out.print(stack.pop()+" ");
System.out.print(stack.pop()+" ");
System.out.print(stack.pop()+" ");

}
}
運行結果:
0 1 2 3 4 5 6 7 8 9 
9 9 8 7 6 

(2)隊列
隊列作爲另一種數據結構,它用先進先出的方式來描述數據的存取方式。
定義:只能在表的一端進行插入操作,在表的另一端進行刪除操作的線性表。

8)Map容器
Map是一個鍵值映射的對象,而且鍵不能相同,不能包含重複的就按,每個鍵最多映射到一個值。
Map通用實現包括:HashMap、TreeMap、LinkedHashMap;
專用實現包括:EnumMap、WeakHashMap、IdentityHashMap
(1)HashMap是基於散列表的實現。插入和查詢“鍵值對”的開銷是固定的,可以通過構造器設置容量和負載因子,以調整容器的性能,如果希望獲取
最大的速度而不關心迭代的順序,可以採用HashMap
HashMap演示:
package LianXi;


import java.util.HashMap;
import java.util.Iterator;
import java.util.Set;


public class ListDemo {

public static void main(String[] args) {
HashMap hm = new HashMap();
hm.put(new Integer(1),"A");
hm.put(new Integer(2), "B");
hm.put(new Integer(3), "C");
hm.put(new Integer(4), "D");
hm.put(new Integer(5), "E");
Set s=hm.keySet();
Iterator i=s.iterator();
while(i.hasNext()){
Object k=i.next();
Object v=hm.get(k);
System.out.println(" "+k+"="+v);
}
}
}
運行結果:
 1=A
 2=B
 3=C
 4=D
 5=E
代碼說明: 輸出的結果的順序與加入鍵值對的順序沒有必然的聯繫。我們先獲取Key的一個Set,然後用迭代器訪問Set取出Key。再用Key去得到value
,這是訪問Map所有元素的一種方法。

(2)TreeMap

TreeMap繼承於AbstractMap,同時實現了SortedMap接口,這與前面提到的TreeSet相似,而且在處理由TreeMap的keySet()方法得到的集合與TreeSet相同。TreeMap的訪問

方法與HashMap相同,而且不管元素加入的順序如何,最後輸出的結果總是按照鍵(Key)從小到大排列的,因此要求Key實現Comparable接口,並且更重要的是相互之間

是可比的。

TreeMap示例:

package LianXi;


import java.util.Iterator;
import java.util.Set;
import java.util.TreeMap;


public class ListDemo {

public static void main(String[] args) {
TreeMap tm1= new TreeMap();
TreeMap tm2=new TreeMap();
//tm1和tm2元素的輸入順序不同
tm1.put(new Integer(1), "A");
tm1.put(new Integer(2), "B");
tm1.put(new Integer(3), "C");
tm1.put(new Integer(4), "D");
tm1.put(new Integer(5), "E");
tm2.put(new Integer(5), "E");
tm2.put(new Integer(3), "C");
tm2.put(new Integer(4), "D");
tm2.put(new Integer(1), "A");
tm2.put(new Integer(2), "B");
//通過集合+迭代器的方法來遍歷TreeMap對象tm1
Set s1=tm1.keySet();
Iterator i1= s1.iterator();
while(i1.hasNext()){
Object k=  i1.next();
   Object v= tm1.get(k);
   System.out.print(" "+k+"="+v);
}
System.out.println();
//通過集合+迭代器的方法來遍歷TreeMap對象tm2
  Set s2=tm2.keySet();
  Iterator i2= s2.iterator();
  while(i2.hasNext()){
Object k=  i2.next();
Object v= tm2.get(k);
System.out.print(" "+k+"="+v);
  }
}
}

//運行結果

 1=A 2=B 3=C 4=D 5=E
 1=A 2=B 3=C 4=D 5=E

(3)LinkedHashMap

LinkedHashMap提供了LinkedHashSet不具備的兩個功能:第一,當創建LinkedHashMap時可以按照鍵訪問進行排序,即與被很少查看的值關聯的鍵被安排到Map的末尾;

第二,LinkedHashMap提供removeEldestEntry方法(),可以覆蓋這個方法,以便在新的映射對加入到Map時自動強制地刪除舊映射對的策略。

LinkedHashMap演示實例:

package LianXi;


import java.util.LinkedHashMap;
import java.util.Map;


public class MyLinkedHashMap extends LinkedHashMap {
private final int Capacity;
//ListDemo構造函數
public MyLinkedHashMap(int maxCapacity){
super(maxCapacity,0.75f,true);
//LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder) 
        //構造一個帶指定初始容量、加載因子和排序模式的空 LinkedHashMap 實例。
Capacity=maxCapacity;
}
//重載removeEldestEntry()方法,使ListDemo的實例最多容納Capacity個元素
protected boolean removeEldestEntry(Map.Entry eldest){
return this.size()>Capacity;
}
}


package LianXi;


public class ListDemo{
public static void main(String ags[]){
MyLinkedHashMap mym=new MyLinkedHashMap(5);
//初始化MyLinkedHashMap
mym.put(new Integer(1), "A");
mym.put(new Integer(2), "B");
mym.put(new Integer(3), "C");
mym.put(new Integer(4), "D");
mym.put(new Integer(5), "E");
System.out.println("初始化Map序列:"+mym);
//通過get操作將前3個元素依次放到Map頭部,最後被放在頭部的是第3個元素
for(int i=1;i<4;i++){
mym.get(new Integer(i));
}
System.out.println("移動隊尾3個元素後的Map序列:"+mym);
//添加第6個元素,但是mym的最大值爲5
//所以刪除最不“常用”的元素,即尾部的元素“D”
mym.put(6, "F");
System.out.println("添加新元素替換隊尾元素後的序列"+mym);

}
}

(4)EnumMap

EnumMap在內部實現爲Array,它是用於枚舉鍵的高性能Map實現。這個實現結合了Map接口的豐富功能和安全性以及數組的高速訪問。如果我們希望把枚舉映射到值,就應該

使用EnumMap,而不是數組。

(5)WeakHashMap

WeakHashMap是值存儲對其鍵的弱引用的Map接口實現。

(6)IdentityHashMap

IdentityHashMap是散列表基於標識的Map實現。


8)hashCode()方法

(1)散列碼

散列碼就是一種通過不可逆的散列(Hash)算法對一個鍵(數據)進行計算獲得一個“唯一”的值,並將這個值放入散列表中。這個值可以對這個鍵(數據)進行標識。在

查找鍵(數據)的時候,可以通過散列表中的此值來快速定位鍵(數據),從而有效減少開銷

散列算法就是一種用於實現散列的方法,它接受一個查找鍵(數據),計算出該鍵(數據)的散列碼,然後再將此散列碼壓縮到散列表的範圍內。總之,使用散列的目的在於:

想要使用一個對象查找另一個對象。

(2)Java中的hashCode()方法

對於HashMap,Java將鍵-值中的“鍵”作爲輸入數據進行散列,並形成散列表。Java中的對象都繼承於基類Object,Object類有一個方法hashCode(),它默認是使用對象的地址作爲散列算法的輸入,返回一個整數散列碼,所以Java中每個類都有此方法。

hashCode()方法是根據對象的內存地址來返回一個散列碼,這樣內容不同的對象實例就會返回不同的散列碼,一般我們在構建自己的類時需要重寫此方法。重載hashCode()

方法的同時需要重載Object類中另一個方法equals()。HashMap使用equals()判斷當前的“鍵”是否與表中存在的“鍵”相同。重載hashCode()方法需要遵循以下原則:

《1》如果某個類覆蓋了hashCode(),那麼它也應該覆蓋equals(),反之亦然。

《2》如果equals()返回相同的值,那麼hashCode()也應該返回相同的值

《3》在同一個程序的兩次執行中,對象的散列碼可以不同

(3)重載hashCode()方法的常用散列算法

對於字符串散列碼的計算一般採用如下方法:將每個字符的Unicode值乘以一個該字符在字符串的位置的因子,散列碼就是所有這些乘積的和。Java中的String的hashCode()

就是用常數31作爲因子。

對於基本類型的散列碼的計算,一般都是轉化爲int型。在Java中對於long型的數據,一般是用移位操作將64位的值轉換爲32位的int值。對於double和float類型,一般用其

封裝類的Double.doubleToLongBits(key)或者Float.floatToLongBits(key),然後通過移位和異或來完成

重載hashCode()方法演示:

package LianXi;


import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;


public class ListDemo{
private static List created = new ArrayList();//創建一個ArrayList對象created
private String s;
private int id=0;
ListDemo(String str){
s=str;
created.add(s);
Iterator it = created.iterator();
while(it.hasNext()){
if(it.next().equals(s))
id++;
}
}
public String toString(){ //定義toString方法
return "String: "+s+"id: "+id+"hashCode():"+hashCode();
}
public int hashCode(){//重載hashCode()方法
int result=17;
result=37*result+s.hashCode();
result=37*result+id;
return result;
}
public boolean equals(Object o){//重載equals()方法
return (o instanceof ListDemo)&&s.equals(((ListDemo)o).s)&&id==((ListDemo)o).id;
//instanceof通過返回一個布爾值來指出,這個對象是否是這個特定類或者是它的子類的一個實例。
}
public static void main(String ags[]){
Map map =new HashMap();
ListDemo[] ld=new ListDemo[10];
for(int i=0;i<ld.length;i++){
//實例化10個CountedString對象,且其String值是一樣的,而id值不一樣
ld[i]=new ListDemo("hi");
//利用ListDemo作爲hashMap的鍵
//在填充hashMap容器的時候,自動調用hashCode(),計算散列碼
map.put(ld[i], new Integer(i));
}
//輸出map,輸出結果不是按輸入順序進行輸出的
System.out.println(map);
for(int i=0;i<ld.length;i++){
System.out.print("Looking up"+ld[i]+"value==");
System.out.println(map.get(ld[i]));
}
}
}

9)迭代器

迭代器(Iterator)是一個對象,它的工作是遍歷並選擇序列中的對象,它提供一種方法訪問一個容器(Container)對象中各個元素,而又不需要暴露該對象的內部細節。

此外,迭代器通常被稱爲“輕量級”對象,因爲創建它的代價小。因此經常見到對迭代器有限制,例如:某些迭代器只能單向移動

(1)迭代器的使用

使用方法Iterator(),容器返回一個Iterator的next()方法時,它返回序列的第一個元素。

用next()獲取序列中的下一個元素,並將遊標(Cursor)向後移動

使用hasNext()檢查序列中是否還有元素

使用remove()將上次返回的元素從迭代器中移除

ListIterator從Iterator繼承了next()、hasnext()和remove()3個方法,hasPrevious()和previous()模擬了hasnext()和next(),只是方向不同。hashnext()和next()指向遊標之後

的元素,而hasPrevious()和Prevous()指向遊標之前的元素

(2)迭代器的主要用法:

首先用hasNext()作爲循環條件,再用next()方法得到每個元素,最後再進行相關的操作。

10)HashMap和HashTable的區別

(1)HashTable的方法是同步的,HashMap不能同步

(2)HashTable不允許null值(key和value都不可以),HashMap允許null值(key和value都可以)

(3)HashTable有一個contains()方法,功能和containsValue()功能一樣

(4)HashTable使用Enumeration,HashMap使用Iterator

(5)hash數組的初始化大小及其增長方式不同

(6)哈希值的使用不同,HashTable直接使用對象的hashCode,而HashMap會重新計算hash值







發佈了38 篇原創文章 · 獲贊 16 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章