關於在TreeSet中新增自定義類 報ClassCastException的解決方法

風過留痕丶發表於2014-07-17

 一、先來看一下TreeSet的繼承結構和類宣告形式

繼承結構:

java.lang.Object 
   |_ java.util.AbstractCollection<E> 
        |_ java.util.AbstractSet<E> 
              |_ java.util.TreeSet<E> 

類宣告:
public class TreeSet<E> 
    extends AbstractSet<E> 
    implements SortedSet<E>, Cloneable, java.io.Serializable //它實現了sortedSet,有排序的功能

 

二、TreeSet的主要性質


1、TreeSet中不能有重複的元素;

2、TreeSet具有排序功能;

3、TreeSet中的元素必須實現Comparable介面並重寫compareTo()方法,TreeSet判斷元素是否重複、以及確定元素的順序靠的都是這個方法;(這條性質比較重要,如果讀者對TreeSet內部機制比較熟悉的話這條性質應該不難理解;如果讀者不太理解的話可以參看以下這篇文章http://wlh269.javaeye.com/blog/376430)

4、對於java類庫中定義的類,TreeSet可以直接對其進行儲存,如String,Integer等(因為這些類已經實現了Comparable介面);

5、對於自定義類,如果不做適當的處理,TreeSet中只能儲存一個該型別的物件例項,請看程式示例:

import java.util.*;
public class TreeSetDemo{
 public static void main(String args[]){
  TreeSet<Demo> tSet=new TreeSet<Demo>();
  Demo d1=new Demo(1,"abc");
  Demo d2=new Demo(2,"xyz");
    
  tSet.add(d1);
  tSet.add(d2);//如果有這條語句,執行程式時會丟擲ClassCastException異常
                       //如果沒有這條語句,程式會正常執行,並輸出d1的內容
  Iterator itr=tSet.iterator();
  while(itr.hasNext()){
   Demo d=(Demo)itr.next();
   System.out.print(d.a+" "+d.b);
   System.out.println();
  }
 } 
}
class Demo{
 int a;
 String b;
 public Demo(int a,String b){
  this.a=a;
  this.b=b;
 }
}

三、在TreeSet中儲存自定義類的實現方法

示例:

import java.util.*;
public class TreeSetDemo{
 public static void main(String args[]){
  TreeSet<Demo> tSet=new TreeSet<Demo>();
  Demo d2=new Demo(2,"xyz");
  Demo d3=new Demo(2,"uvw");

  Demo d1=new Demo(1,"abc");
  
  tSet.add(d1);
  tSet.add(d2);
  tSet.add(d3);


  Iterator itr=tSet.iterator();
  while(itr.hasNext()){
   Demo d=(Demo)itr.next();
   System.out.print(d.a+" "+d.b);//注意此程式執行時會輸出幾個元素
   System.out.println();
  }
 } 
}
class Demo implements Comparable{
 int a;
 String b;
 public Demo(int a,String b){
  this.a=a;
  this.b=b;
 }
  public int compareTo(Object o){
   Demo demo=(Demo)o;
  if(this.a>demo.a){
   return 1;
  }else if(this.a<demo.a){
   return -1;
  }else{
   return 0;
  }
 }
}

解析:上面程式會輸出兩個元素,並且是以a為判斷標準按序輸出的。當呼叫TreeSet的add()方法時,在TreeSet的內部會間接呼叫Demo的compareTo()方法、然後和TreeSet中已經存在的其他元素一一進行比較,在比較的過程中完成“判斷是否重複”以及“排序”的功能:當在某次比較的過程中發現compareTo()返回0,就會認為待加入的元素已經存在於TreeSet中,返回-1或1的話就會根據TreeSet預設的比較器進行排序。

 

下面對程式進行修改,重寫compareTo()方法,讓TreeSet以a和b兩個屬性為依據來判斷元素是否重複以及元素的順序,請看下面的示例:

import java.util.*;
public class TreeSetDemo{
 public static void main(String args[]){
  TreeSet<Demo> tSet=new TreeSet<Demo>();
  Demo d1=new Demo(1,"abc");
  Demo d2=new Demo(2,"xyz");
  Demo d3=new Demo(2,"uvw");
  
  tSet.add(d1);
  tSet.add(d2);
  tSet.add(d3);
  
  Iterator itr=tSet.iterator();
  while(itr.hasNext()){
   Demo d=(Demo)itr.next();
   System.out.print(d.a+" "+d.b);//注意這次輸出的元素個數
   System.out.println();
  }
 } 
}
class Demo implements Comparable{
 int a;
 String b;
 public Demo(int a,String b){
  this.a=a;
  this.b=b;
 }
  public int compareTo(Object o){
   Demo demo=(Demo)o;
   if(this.a==demo.a&&this.b.equals(demo.b)){
   return 0;
  }else if(this.a>demo.a){
   return 1;
  }else {
   return -1;
  }
 }
}

解析:這次改動了compareTo()方法,程式輸出了三個元素d1,d2和d3;當我們自己定義類,並且需要將自定義的類存到TreeSet中的時候,需要認真考慮compareTo的定義方式即需要認真考慮實際應用中依據什麼判斷元素是否重複和元素的順序。


轉載自lubiaopanlubiaopan的csdn部落格  測試通過程式沒有問題 這裡表示感謝

相關文章