徐秀勤

摘要:本文基于集合學習,介紹如何設計一個比較完善的應用類。通過HashSet介紹了在應用類中添加equals0方法和hashCode()方法,通過TreeSa介紹了應用類需要實現Comparable接口并實現繼承的compareTo()方法。
關鍵詞:集合;類;教學設計
中圖分類號:G642 文獻標識碼:A
文章編號:1009-3044(2019)27-0087-02
集合(Set)是Java中一個很重要的可以用來存儲和處理無重復元素的高效的數據結構。比如說可以存儲和處理一個單位的部門名稱,存儲和處理一個國家的省城名稱,或者奧運會時參賽國家的名稱等,這幾個信息的處理都是要求不可重復的。那么在實際應用中,使用集合存儲和處理相關問題時,應該如何設計這個應用類,確保其元素不可重復存儲呢?
1集合Set
集合Set是一個接口,它繼承了Collection接口中所有的方法。Set接口本身不能實例化,但是可以作為類型使用,只是規定其實例不能包含重復的元素。在一個集合中,當要添加一個新元素時,要先判斷這個元素的散列碼(hashcode值)在原集合的哈希表中是否存在。如果不存在,則新元素可以立即加入;如果存在,則再檢查equals()方法,即新元素通過調用其自身的equals()方法,跟原集合中所有的元素都進行比較,如果存在結果為true的情況,則新元素不能加入,否則新元素可以加入。
Set有三個實現的具體的子類,分別是HashSet、Hnked-HashSet和TreeSet,這三個類也是必須確保不能向集合中添加重復的元素。關于集合的操作與訪問是集合教學的一個重要方面,但是本文限于篇幅不作特別介紹。
2散列集HashSet
HashSet是一個實現了Set接口的散列集,可以使用它的無參構造方法來創建空的散列集,也可以由一個現有的集合來創建一個散列集。HashSet類的實例用來存儲互不相同的任何元素,但允許null元素。該集合的元素是無序的、高效率的。在教學過程中,為讓學生理解這個特點,會創建一個HashSet實例,存放一些字符串對象并輸出集合,具體見【示例1】。
【示例1】主要代碼如下:
Set set=Hew HashSet();//創建一個空集合,可以放任何對象
set.add(”南京“)//將字符串對象“南京”存人集合set中
set.add(”南京”);//這個“南京”不會重復存入集合中;
set.add(“Nanjing”);//將字符串對象“Nanjing”存人集合set中
set.add(“nanjing”);//將字符串對象“nanjing”存人集合set中,注意與“Nanjing”不同
setl.add(12);//12會被包裝成對象存入集合set中,
svstem.out.println(setl;//輸出集合set中所有元素
上述程序代碼最終運行結果顯示集合中只有“南京、Nan-jing、nanjing、12”這四個元素。多次運行,會發現次序有變化,但是元素不變。能達到這效果的原因是,String類已經重寫了equal()方法與hashCode()方法,排除了重復的元素。
那么如果集合set中存儲圓類對象,能確保不重復嗎?首先設計【示例2】圓類如下:
class Circle{
private double r;
Circle(double r){this.r=r;}
//省略r的get、set方法與求面積與周長等其他方法;
pubhc String toString0{return”r=”+r;}//重寫這個方法,顯示圓對象信息
}
在【示例1】的最后輸出語句之前添加兩行相同的代碼"set.add(new Cirlce(5));”
重新運行【示例1】程序,會發現輸出的集合元素中會出現兩個“r=5.0”:
為避免上述問題,需要改寫【示例2】的Cidce類,重寫equals()方法與hashCode()方法。在講授這個集合內容之前,學生已經掌握了如何正確寫出Circle類的equals方法。由此可以先讓學生在Cirlce類中正確添加equals()方法后,再次運行【示例1】,發現兩個半徑為5的圓依然存在。說明一個類僅僅重寫equals()方法是不夠的,必須還要重寫hashCode()方法。該方法原型如下:
public int hashCode(){}
hashCode()方法其實就是要求返回一個整型的散列碼(hashCode值)。要求相同對象的散列碼一樣即可,意味著不相同的元素的散列碼可以一樣也可以不一樣。對于一個由半徑值來描述圓的對象,半徑相同其散列碼相同即可。那么直接將半徑取整返回即可,hashCode()方法代碼如下:
pubhc im hashCode(){return(inI)r;}
上述代碼表示,假如圓半徑的整數部分相同,則它們的散列碼相同,在集合中會再去處理equals方法,才能判斷它們究竟算不算相同的對象。例如半徑為5.00000-5.99999,它們的散列碼都是5。如果圓半徑精度要求達到4位小數,那么為了提高效率,可以考慮把半徑值擴大后再取整返回即可,修改代碼如下:
public im hashCode(){return(inI)(r*10000);}
當然還有其他方法,可以利用String類中已經實現的hash-Code()方法,把double類型的r轉換成String類型,則可以直接調用其本身的hashCodeO方法即可。因此Circle類中的hashCode()方法還可以修改如下:
public int hashCode0{return(r+””).hashCode();J
在教學過程中發現,學生重寫某個類的hashCode方法總是不知如何下手,其實只要確保某元素重要屬性值相同,其散列碼相同即可。想辦法把類中描述元素的重要屬性值轉換成整型數據返回或轉換成字符串調用其hashCode()方法返回即可,非常簡單。
3鏈式集合LinkedHashSet
LinkedHashSet是HashSet的子類,它支持集合內的元素是有序的,不過這個次序是按照集合添加元素的次序的方式排序的。復制【示例1】得到【示例3】,并修改第一行代碼:
Set set=new LinkedHashSet();
其余代碼不變,運行【示例3】,多次運行,發現輸出的集合中的元素沒有重復,且與添加的順序一致,這個特點學生還是比較容易理解并接受的。
4樹形集合TreeSet
Set接口的一個子接口SortedSet可以確保集合中的元素是有序的。TreeSet實現了SortedSet接口,通過無參構造方法可以創建一個空的TreeSet對象。只要對象是可以比較的,就可以將它們添加到一個TreeSet對象中。先設計一個只能添加字符串對象的TreeSet對象,讓學生理解TreeSet與HashSet的不同特點。
【示例4】主要代碼如下:
Setset=new TreeSet();//考慮集合只能存人String對象
set.add("naniing");
在實際應用中,如果需要用集合來存儲和處理對象,則該對象的原類除了包含正常封裝的數據成員,一些必要的業務處理的方法外,還需要重寫hashCode()和equals()方法;如果業務上還要求需要有序存儲,那么對象的原類還必須實現compara-ble接口,實現從接口繼承的compareTo()方法。通過集合基本特點的介紹,希望大家對如何設計一個相對比較完善的應用類能有所幫助。
【通聯編輯:光文玲】