(CompareTo, Compare,hashCode,equals函數)持有對象與公有比較函數
(一), int CompareTo(Object o)的介紹
此函數沒有缺省值,必須自己定義它。表示調用此函數的對象與傳入的另一個對象o做比較,若返回負值(表示此對象小於傳入的對象,事實並沒有所謂的大小之分)則在數組或容器中將此對象放在傳入的對象前面,若返回正值則所放的位置相反,若返回0則不改變位置。
(二):數組的排序和找查
(二.一), 對數組進行排序時系統自動調用int CompareTo(Object o)函數的情況
設a是一個儲存對象的數組,A是a的一元素;
當使用函數Arrays.sort(a);來爲a排序時,系統就會調用a[0]的intCompareTo(Object o)函數,並且逐一以a[1],a2],a[3]直至a[a.length-1]作爲參數輸入。因此a[0]調用int CompareTo(Object o)的次數是a.length-1。
同理,a[1]也會以a[2],a3],a[4] 直至a[a.length-1]作爲參數調用a[1]的int CompareTo(Object o)函數。同理,a[1]調用int CompareTo(Object o)的次數是a.length-2。依次類推。當然a[1]與a[2]和其他元素調用int CompareTo(Object o)函數是交叉進行的。
(二.二), 對數組進行排序時對數組元素的要求
系統會將數組的元素向上轉型至Compararable, 然後用轉型後的對象調用int CompareTo(Object o)。因此數組內的所有元素所在的類必須實現接口Compararable並且複寫int CompareTo(Object o),因此數組也不能有空元素。
(二.三), 對數組元素進行找查時系統自動調用int CompareTo(Object o)函數的情況
當使用函數Arrays.binarySearch(a,A);來找查數組a是否存在元素A時,則系統會以A爲參數逐一調用從a[0]開始至a[a..length-1]的int CompareTo(Object o)函數,當然若找到A就不再調用。
(二.四), 對數組進行找查時對數組元素的要求
數組的元素的int CompareTo(Object o)函數必須能夠有效地起到比較作用,才能保證能找到目標。比如,每個元素的int CompareTo(Object o)不管任何情況都返回正值的話,那麼根據函數Arrays.binarySearch(a,A)自動調用函數int CompareTo(Object o)的流程,可知最終將發生邏輯矛盾(因爲,至少,一定會以元素本身作爲參數調用本身的int CompareTo(Object o)函數),發生邏輯矛盾就不可能找到目標。
(二.五), 對數組元素進行找查後的結果
設有三個相同的元素,a[11]=A1,a[12]=A2,a[13]=A3。找查A1時可以得出它的位置是11,找查A2,A3同理得出它的位置是11,因爲比較函數int CompareTo(Object o) 相同,輸入的參數也相同。所以找查得出的位置的後面纔可能有相同元素,前面不可能有相同元素。
(二.六), 注意int compareTo(Object o)函數內是否有轉型動作
int CompareTo(Object o)函數裏面通常有轉型動作,把o轉型。因此數組中如果有多種對象元素且int CompareTo(Object o)函數裏面有轉型動作就不能用Arrays.sort(Object[] a)和Arrays.binarySearch(Object[] a, Object key
)來排序和找查,否則將發生執行期錯誤。要使用函數 sort(
Object [] a,Comparato c)
和
Arrays.binarySearch (Object[] a, Object key, Comparato c)
。利用函數int
compare(Object o1, Object o2)進行元素的
排序和找查。
(二.七), int compare(Object o1, Object o2)的介紹
此函數沒有缺省值,必須自己定義它。調用此函數的對象並不做比較,把傳入的兩個對象o1,o2做比較,若返回負值(表示此o1小於o2,事實並沒有所謂的大小之分)則在數組或容器中把o1放在o2的前面,若返回正值則所放的位置相反,若返回0則不改變位置。
(二.八), 對數組進行排序時系統自動調用int
compare(Object o1, Object o2)函數的情況
當使用函數sort(
Object [] a,Comparato c)
;來爲a排序時系統就會調用c的compare(Object o1, Object o2)函數,並且逐一以(a[0],a[1]), (a[0],a[2])直至(a[0],a[a.length-1])作爲參數輸入。a[0] 作爲參數的次數是a.length-1。
同理,c會以(a[1],a[2]), (a[1],a[2])直至(a[1],a[a.length-1])作爲參數調用compare(Object o1, Object o2)函數。同理,a[1] 作爲參數的次數是a.length-2。依次類推。當然以a[0]與a[1]和其他元素作爲第一個參數調用c的compare(Object o1, Object o2)函數是交叉進行的。
(二.九), 對數組進行找查時對數組元素的要求
因爲比較函數是由對象c提供的,因此數組排序時數組內可以有空元素,可以不復寫int CompareTo(Object o)函數的元素,有可以有不同的元素,可以是任何對象元素。對數組元素沒有任何要求。當然,c的compare(Object o1, Object o2)函數不能對o1,o2進行轉型。
(二.十), 對數組元素進行找查時系統自動調用int
compare(Object o1, Object o2)函數的情況
Arrays.binarySearch ( a, A, c)
;來找查數組a是否存在元素A時,則系統會以A爲第二個參數分別以a[0]至a[a..length-1] 爲第一個參數逐一調用c的compare(Object o1, Object o2)函數。當然若找到A就不再調用。
(二.十一), 對數組進行找查時對數組元素的要求與結果
要求:當然,c的compare(Object o1, Object o2)函數和int CompareTo(Object o)函數一樣,必須提供有效的比較方式,才能保證找到目標。
結果:設有三個相同的元素,a[11]=A1,a[12]=A2,a[13]=A3。找查A1時可以得出它的位置是11,找查A2,A3同理得出它的位置是11,因爲比較函數compare(Object o1, Object o2)相同,輸入的參數也相同。所以找查得出的位置的後面纔可能有相同元素,前面不可能有相同元素。
(三):List排序和找查
Collections和Arrays一樣,Arrays爲數組提供一些操作函數,Collections就爲List和Set提供一些操作函數。但Collections只爲List提供元素的排序和找查,因爲Set並不需要。
在不排序的情況下,第一加入的元素對應的序列號爲0,第二加入的元素對應的序列號爲1,依次類推。
對它排序可以使用函數Collections.sort(List list), Collections.sort(List list,Comparato c)。
對它的元素進行找查可以使用函數Collections.binarySearch (List list,Object key), Collections.binarySearch (List list,Object key,Comparato c)。
用sort和binarySearch對List排序和找查和用sort和binarySearch對數組進行排序和找查,程序的要求,過程,結果,完全一模一樣。
(三)TreeSet加入對象
intCompareTo(Object o)函數不僅用來確定TreeSet元素的次序,而且用來確定TreeSet元素的獨一無二。
TreeSet的一個對象tS,用tS.add(Object o),加入對象時,系統就會調用加入的對象o的intCompareTo(Object o)函數,並且沒有次序地把已經加入的對象作爲參數輸入。直到確定tS裏面元素的次序,然後停止調用o的intCompareTo(Object o)函數。若intCompareTo(Object o)函數返回0值,則不將對象o加入,而不是用o來代替與o相同的對象。
也就是說TreeSet加入對象後,TreeSet裏面元素的唯一性和元素的次序就得到了確定。
(四)TreeMap加入對象與取出對象
intCompareTo(Object o)函數不僅用來確定TreeMap的key值次序,而且用來確定key值的獨一無二。
TreeMap的一個對象tM,用tM.put(Object key,Object value),加入對象時,系統就會調用key的intCompareTo(Object o)函數,並且沒有次序地把已經加入的鍵值對象作爲參數輸入。直到確定tM裏面鍵值對象的次序,然後停止調用key的intCompareTo(Object o)函數。若intCompareTo(Object o)函數返回0值,則將key加入並且加入它對應的value值,代替覆蓋與key相同的鍵值對象和用value值代替它的實值。
用tM.get(Object key)來取它對應的實值時,系統也會調用key的intCompareTo(Object o)函數,並且沒有次序地把已經加入的鍵值對象作爲參數輸入,用來找查和確定是否有鍵值和這個key對應,有則調用對應這個key的鍵值的實值。
(五),int hashCode()函數的介紹
int hashCode()函數存在每一個類中,表示根據它的返回值產生一個int型整數(即hash code)來代表這個對象。在缺省的狀態下,int hashCode()函數會爲每一個對象產生一個無二的hash code。若複寫int hash code()函數,則系統會根據它的返回值來產生hash code代表對象,不同的的返回值會得到不同的hash code,相同的的返回值會得到相同的hash code不論是否在同一個包中或其他情況,返回值相同hash code則相同,但注意返回值與所得到的hash code的值是不相同的。
(六),int hashCode()函數的與Stirng toString()函數的關係
當對象轉化爲字符串時,即用字符串的形式表示對象時(注意不是把它轉型成String類),系統會先自動調用此對象的String toString()函數。缺省的String toString()函數會用“包名+類名+@+hash code”的字符串來代表調用它的對象。所以,設hC是一個對象的話,象這樣的動作:String s=""+hC; System.out.println(hC); 系統都會自動先調用hC的String toString()函數,後再調用hC的int hashCode()函數,因爲要獲取hC的hash code 它的String toString()函數裏面會調用hC的int hashCode()函數。即缺省的String toString()函數會調用hC的int hashCode()函數。若複寫了String toString()函數,當對象轉化爲字符串時,就不一定會調用int hashCode()函數了。
(七),boolean equals(Object obj)函數的介紹
boolean equals(Object obj)函數存在每一個類中,它表示調用此函數的對象與傳入的對象obj做比較,若返回true(就說這兩個對象相等,事實上除了它本身沒有一個對象和它真正相等)則容器就把這兩個對象當作同一元素對待。若返回false,則容器就認爲這兩個對象是兩個不同的元素。在缺省的狀態下,boolean equals(Object obj)函數除了把調用它的對象作爲參數輸入會返回true,否則使用其他對象作爲參數都會返回false。
(八),HashSet加入對象
(1),HashSet的一個對象hS,用hS.add(Object o),加入對象時,由於要確定每個元素的唯一性,系統就會首先自動調用對象o的int hashCode()函數。
(2),然後會把得到的o的hash code值與已經加入容器的對象的hash code值做比較(注意:比較的只是hash code值而不是對象的字符串表達式的比較,而且這一過程看不見)。如果將要加入的對象o的hash code值與已經加入的容器裏面的任意一個對象的hash code值不同,則將對象o加入容器。
(3),如果有對象的hash code值與o的hash code值相同,則系統會再自動調用0的boolean equals(Object obj)函數,並且按對象加入容器的次序的相反順序(即後加入的先作參數)逐一把所有這些與對象o的hash code值相同的對象作爲參數,來進行比較。
(4),如果o的boolean equals(Object obj)函數的所有返回值都是false則將對象o加入容器。
如果返回值出現true,則將對象o代替這時作爲boolean equals(Object obj)的參數的對象加入容器,即用o覆蓋這時的參數obj。然後終止調用o的boolean equals(Object obj)函數。
如果這些參數中,含有對象o本身,則在對象o作爲自己的函數的參數開始調用本身的boolean equals(Object obj)函數時,系統會自動終止o的boolean equals(Object obj)函數的調用,然後不把對象o再次加入容器。
(5),即hS.add(Object o),加入對象時,要調用boolean equals(Object obj)函數的條件是: hash code值不相同和參數不能爲本身。
(九)HashMap加入對象與取出對象
(1)HashMap加入對象
(1.1),HashMap的一個對象hM, 用hM.put(Object key,Object value),加入對象時,由於要確定每個key值的唯一性,系統就會首先自動調用對象key的int hashCode()函數。
(1.2),然後會把得到的對象key的hash code值與已經加入容器的鍵值對象的hash code值做比較(注意:比較的只是hash code值而不是對象的字符串表達式的比較,而且這一過程看不見)。如果將要加入的對象key的hash code值與已經加入的容器裏面的任意一個鍵值對象的hash code值不同,則將對象key和value加入容器。
(1.3),如果有鍵值對象的hash code值與key的hash code值相同,則系統會再自動調用key的boolean equals(Object obj)函數,並且按對象加入容器的次序的相反順序(即後加入的先作參數)逐一把所有這些與對象key的hash code值相同的鍵值對象作爲參數,來進行比較。
(1.4),如果key的boolean equals(Object obj)函數的所有返回值都是false則將對象key和value加入容器。
如果返回值出現true,則將對象key代替這時作爲boolean equals(Object obj)的參數的鍵值對象加入容器,即用key覆蓋這時的參數obj,然後用key對應的實值value覆蓋此時的obj對應的實值。最後終止調用key的boolean equals(Object obj)函數。
如果這些參數中,含有對象key本身,則在對象key作爲自己的函數的參數開始調用本身的boolean equals(Object obj)函數時,系統會自動終止o的boolean equals(Object obj)函數的調用,然後鍵值保持不變用新實值覆蓋舊覆蓋。
(1.5),即hM.put(Object key,Object value),加入對象時,要調用boolean equals(Object obj)函數的條件是: hash code值不相同和參數不能爲本身。
(2)HashMap取出對象
(2.1),HashMap的一個對象hM, hM.get(Object key)來取它對應的實值時,由於要確定容器內是否有鍵值和這個key對應,,系統就會首先自動調用對象key的int hashCode()函數。
(2.2),然後會把得到的對象key的hash code值與已經加入容器的鍵值對象的hash code值做比較(注意:比較的只是hash code值而不是對象的字符串表達式的比較,而且這一過程看不見)。如果對象key的hash code值與已經加入的容器裏面的任意一個鍵值對象的hash code值不同,則容器內沒有與key對應的鍵值,取出的值是null。
(2.3),如果有鍵值對象的hash code值與key的hash code值相同,則系統會再自動調用key的boolean equals(Object obj)函數,並且按對象加入容器的次序的相反順序(即後加入的先作參數)逐一把所有這些與對象key的hash code值相同的鍵值對象作爲參數,來進行比較。
(2.4),如果key的boolean equals(Object obj)函數的所有返回值都是false則容器內沒有與key對應的鍵值,取出的值是null。。
如果返回值出現true,則取出此時作爲boolean equals(Object obj)的參數的鍵值對象所對應的實值。然後終止調用key的boolean equals(Object obj)函數。
如果這些參數中,含有對象key本身,則在對象key作爲自己的函數的參數開始調用本身的boolean equals(Object obj)函數時,系統會自動終止key的boolean equals(Object obj)函數的調用,並取出key對應的實值。
(2.5), 要調用boolean equals(Object obj)函數的條件是: hash code值不相同和參數不能爲本身。
最後:知道這些過程就能有效的定義這些函數了。哈哈!