先看下面一段代碼:
package 類集; import java.util.Set; import java.util.TreeSet; class Person{ private String name ; private int age ; public Person(String name,int age){ this.name = name ; this.age = age ; } public String gtoString(){ return "姓名:" + this.name + ";年齡:" + this.age ; } }; public class test1{ public static void main(String args[]){ Set<Person> allSet = new TreeSet<Person>() ; allSet.add(new Person("張三",30)) ; allSet.add(new Person("李四",31)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("趙六",33)) ; allSet.add(new Person("孫七",33)) ; System.out.println(allSet) ; } };
運行結果:
Exception in thread "main" java.lang.ClassCastException: 類集.Person cannot be cast to java.lang.Comparable at java.util.TreeMap.compare(TreeMap.java:1294) at java.util.TreeMap.put(TreeMap.java:538) at java.util.TreeSet.add(TreeSet.java:255) at 類集.test1.main(test1.java:19)
報錯。此時沒有排序,因為java.lang.comparable類導致。
comparable是進行排序的接口。一個對象數組要想排序需要依靠comparable接口完成。對於treeset一樣,要想進行排序,則對象所在的類也要依靠comparable接口。
修改如下,要想排序,對象所在的類也要依靠comparable接口(繼承之)。
package 類集; import java.util.Set; import java.util.TreeSet; class Person implements Comparable<Person>{ private String name ; private int age ; public Person(String name,int age){ this.name = name ; this.age = age ; } public String toString(){ return "姓名:" + this.name + ";年齡:" + this.age ; } public int compareTo(Person per){ //這里需要復習comparable接口的知識 if(this.age>per.age){ return 1 ; }else if(this.age<per.age){ return -1 ; }else{ return 0 ; } } }; public class test1{ public static void main(String args[]){ Set<Person> allSet = new TreeSet<Person>() ; allSet.add(new Person("張三",30)) ; allSet.add(new Person("李四",31)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("趙六",33)) ; allSet.add(new Person("孫七",33)) ; System.out.println(allSet) ; } };
輸出結果:
[姓名:張三;年齡:30, 姓名:李四;年齡:31, 姓名:王五;年齡:32, 姓名:趙六;年齡:33]
string類既然可以使用TreeSet排序,則String中肯定已經實現了Comparable接口。
string類定義如下:
public final class Stringextends Objectimplements Serializable, Comparable<String>, CharSequence
此時是可以排序了,但是結果有問題,
[姓名:張三;年齡:30, 姓名:李四;年齡:31, 姓名:王五;年齡:32, 姓名:趙六;年齡:33]
發現去掉了重復的元素(王五),依靠的是comparable接口完成的。孫七沒有加入進來,因為孫七和趙6年齡是完全一樣的,而此時的comparable接口比較的只是年齡。
為了保證正確,所有的屬性都應該進行比較:改成如下:
package 類集; import java.util.Set; import java.util.TreeSet; class Person implements Comparable<Person>{ private String name ; private int age ; public Person(String name,int age){ this.name = name ; this.age = age ; } public String toString(){ return "姓名:" + this.name + ";年齡:" + this.age ; } public int compareTo(Person per){ if(this.age>per.age){ return 1 ; }else if(this.age<per.age){ return -1 ; }else{ return this.name.compareTo(per.name) ; // 調用String中的compareTo()方法 } } }; public class test1{ public static void main(String args[]){ Set<Person> allSet = new TreeSet<Person>() ; allSet.add(new Person("張三",30)) ; allSet.add(new Person("李四",31)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("趙六",33)) ; allSet.add(new Person("孫七",33)) ; System.out.println(allSet) ; } };
輸出結果:
[姓名:張三;年齡:30, 姓名:李四;年齡:31, 姓名:王五;年齡:32, 姓名:孫七;年齡:33, 姓名:趙六;年齡:33]
此時的去重元素並不是真正意義上的重復元素取消。
用hashSet試試,hashset不排序。
package 類集; import java.util.HashSet; import java.util.Set; class Person{ private String name ; private int age ; public Person(String name,int age){ this.name = name ; this.age = age ; } public String toString(){ return "姓名:" + this.name + ";年齡:" + this.age ; } }; public class test1{ public static void main(String args[]){ Set<Person> allSet = new HashSet<Person>() ; allSet.add(new Person("張三",30)) ; allSet.add(new Person("李四",31)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("趙六",33)) ; allSet.add(new Person("孫七",33)) ; System.out.println(allSet) ; } };
輸出結果:
[姓名:王五;年齡:32, 姓名:趙六;年齡:33, 姓名:孫七;年齡:33, 姓名:王五;年齡:32, 姓名:張三;年齡:30, 姓名:李四;年齡:31, 姓名:王五;年齡:32]
此時並沒有去掉重復的元素,該如何取消呢,
如果要想去掉重復,則需要object類中兩個方法幫助。
1,hashcode():表示一個唯一編碼,一般通過計算表示。
2)equals():進行對象的比較操作。
我們需要覆寫這兩個方法!
package 類集; import java.util.HashSet; import java.util.Set; class Person{ private String name ; private int age ; public Person(String name,int age){ this.name = name ; this.age = age ; } public boolean equals(Object obj){ // 覆寫equals,完成對象比較 if(this==obj){ return true ; } if(!(obj instanceof Person)){ return false ; } Person p = (Person)obj ; // 向下轉型 if(this.name.equals(p.name)&&this.age==p.age){ return true ; }else{ return false ; } } public int hashCode(){ return this.name.hashCode() * this.age ; // 自己定義一個公式,如上所寫。 } public String toString(){ return "姓名:" + this.name + ";年齡:" + this.age ; } }; public class test1{ public static void main(String args[]){ Set<Person> allSet = new HashSet<Person>() ; allSet.add(new Person("張三",30)) ; allSet.add(new Person("李四",31)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("王五",32)) ; allSet.add(new Person("趙六",33)) ; allSet.add(new Person("孫七",33)) ; System.out.println(allSet) ; } };
輸出結果:
[姓名:趙六;年齡:33, 姓名:王五;年齡:32, 姓名:張三;年齡:30, 姓名:李四;年齡:31, 姓名:孫七;年齡:33]
此時沒有了重復元素。
如果要想使用Set,必須注意以上兩個問題,
1,一個好的類應該覆寫object類中的equals(),hashCode(),toString()三個方法,實際上在String()中已經覆寫完成了。
2,Set接口依靠hashCode()和equals()完成重復元素的判斷,關於這一點,在以后的Map接口中也有體現。
3,TreeSet依靠Comparable完成排序的操作。