Java关于一个java.util.TreeSet的问题

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java关于一个java.util.TreeSet的问题相关的知识,希望对你有一定的参考价值。

import java.util.TreeSet;

class Drink implements Comparable
public String name;

public int compareTo(Object o)
return 0;


public class A
public static void main(String[] args)
Drink one = new Drink();
Drink two = new Drink();
one.name= "Coffee";
two.name= "Tea";
TreeSet set = new TreeSet();
System.out.println(set.add(one));
System.out.println(set.size());
System.out.println(set.add(two));
System.out.println(set.size());
for(Object d:set.toArray())
System.out.println(((Drink)d).name);




为什么第二次给set添加的时候失败
越详细越好

你好,看到这种问题,你最好能看看源码,我截取TreeSet代码如下:
public boolean add(E e)
return m.put(e, PRESENT)==null;

public TreeSet()
this(new TreeMap<E,Object>()); //默认构造

HashSet的内部实现就是一个new TreeMap<E,Object>(),继续看TreeMap:
public V put(K key, V value)
Entry<K,V> t = root;
if (t == null)
// TBD:
// 5045147: (coll) Adding null to an empty TreeSet should
// throw NullPointerException
//
// compare(key, key); // type check
root = new Entry<K,V>(key, value, null);
size = 1;
modCount++;
return null;

int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
if (cpr != null)
do
parent = t;
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
while (t != null);

else
if (key == null)
throw new NullPointerException();
Comparable<? super K> k = (Comparable<? super K>) key;
do
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
while (t != null);

Entry<K,V> e = new Entry<K,V>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;

看到这里我想你也明白了吧,这里就对调用对象的compareTo方法,而你的那个方法返回的正好是相等也就是0.所以在put的时候每次的键相同是不可以继续添加的,所以返回是false。
参考技术A 你的这个方法改成这样:
public int compareTo(Object o)
// TODO Auto-generated method stub
return o.hashCode();

就行了。。
因为Set是不能存放相同的值的。。而它是怎么判断值的呢。就是靠的上面的方法。。
你原代码都是返回0的,所以第二次的时候。Set认为你添加的是相同的值。。本回答被提问者采纳

Java SortedSet为什么可以实现自动排序?

Set中的SortedSet(SortedSet为TreeSet的实现接口),它们之间的继承关系如下:

java.util.Set;

java.util.SortedSet; 

java.util.TreeSet; 

SortedSet中的元素无序不可重复,但是存进去的元素可以按照元素大小顺序自动排序。结合以下代码来看:

 

import java.util.*;
import java.text.*;
public class SortedSetTest01{
 public static void main(String[] args)throws Exception{
   SortedSet ss=new TreeSet();
   //数字类
   ss.add(12);
   ss.add(23);
   ss.add(45);
   ss.add(39);
   ss.add(45);
   Iterator it=ss.iterator();
   while(it.hasNext()){
     System.out.println(it.next());
   }
   //String类
   SortedSet str=new TreeSet();
   str.add("JACK");
   str.add("TOM");
   str.add("KING");
   str.add("SUN");
   it=str.iterator();
   while(it.hasNext()){
     System.out.println(it.next());
   }
   //日期类
   String st1="2003-08-12";
   String st2="2004-09-17";
   String st3="2003-04-12";
   String st4="2013-09-04";
   
   SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
   Date t1=sdf.parse(st1);
   Date t2=sdf.parse(st2);
   Date t3=sdf.parse(st3);
   Date t4=sdf.parse(st4);
   
   SortedSet times=new TreeSet();
   times.add(t1);
   times.add(t2);
   times.add(t3);
   times.add(t4);
   
   it=times.iterator();
   while(it.hasNext()){
     Object element=it.next();
     if(element instanceof Date){
       Date d=(Date)element;
       System.out.println(sdf.format(d));
     }
   }
 }
}

 

编译运行后输出:

 

12
23
39
45
JACK
KING
SUN
TOM
2003-04-12
2003-08-12
2004-09-17
2013-09-04

 

以上代码展示了存在SortedSet中的元素可以按照元素大小进行排序,这些元素可以是数字类,字符串类或日期类等。既然知道了SortedSet的这一特性,那么SortedSet集合存储元素为什么可以自动排序?

 

在上面的代码中我们实现了SortedSet中的数字,字符串和日期类的自动排序,那么如果我们自定义几个User类型对象,然后把它们添加到SortedSet集合中去,可以实现像上面那样的自动排序吗?试一下。

 

import java.util.*;
public class SortedSetTest02{
 public static void main(String[] args){
   SortedSet users=new TreeSet();
   User u1=new User(12);
   User u2=new User(16);
   User u3=new User(23);
   User u4=new User(32);
   User u5=new User(43);
   
   users.add(u1);
   users.add(u2);
   users.add(u3);
   users.add(u4);
   users.add(u5);
   Iterator it=users.iterator();
   while(it.hasNext()){
     System.out.println(it.next());
   }
 }
}
class User{
 int age;
 User(int age){
   this.age=age;
 }
 public String toString(){
   return "User[age="+age+"]";
 }
}

 

编译通过,运行后出错,输出:

Exception in thread "main" java.lang.ClassCastException: User cannot be cast to java.lang.Comparable

at java.util.TreeMap.compare(Unknown Source)

at java.util.TreeMap.put(Unknown Source)

at java.util.TreeSet.add(Unknown Source)

at SortedSetTest02.main(SortedSetTest02.java:14)

User cannot be cast to java.lang.Comparable,也就是说User不可以转变成可比较的类型。所以User必须实现Comparable接口(也就是第一个程序例子中数字,字符串,日期底层已经实现了Comparable接口),即class User implements Comparable{ }。我们知道一个类实现一个接口就实现了这个接口的所有方法,SortedSet集合中的元素之所以可以自动排序,是因为使用add()方法添加进去的元素实现了Comparable接口中的CompareTo()方法。

上述代码中,如果我们给定一个需求,按照User的年龄排序,那么就需要编写一个比较规则,

 

public int compareTo(Object o){
   //编写一个比较规则
   int age1=this.age;
   int age2=((User)o).age;
   return age1-age2;
 }

 

compareTo的用法为u1.compareTo(u2),this为u1,括号里的参数o为u2,因为括号里的参数类型为Object类型,而Object类型没有age这个属性,所以必须把o强制类型转换为User类型,即(User)o。修改之后的整体代码如下:

 

import java.util.*;
public class SortedSetTest02{
 public static void main(String[] args){
   SortedSet users=new TreeSet();
   User u1=new User(12);
   User u2=new User(16);
   User u3=new User(23);
   User u4=new User(32);
   User u5=new User(43);
   
   users.add(u1);
   users.add(u2);
   users.add(u3);
   users.add(u4);
   users.add(u5);
   Iterator it=users.iterator();
   while(it.hasNext()){
     System.out.println(it.next());
   }
 }
}
class User implements Comparable{
 int age;
 User(int age){
   this.age=age;
 }
 public String toString(){
   return "User[age="+age+"]";
 }
 //实现java.lang.Comparable;接口中的compareTo方法
 //该方法程序员负责实现,SUN提供的程序已经调用了该方法
 //需求:按照User的年龄排序
 public int compareTo(Object o){  //u1.compareTo(u2)
   //编写一个比较规则
   int age1=this.age;   
   int age2=((User)o).age;
   return age1-age2;
 }
}

 

编译运行后输出:

 

User[age=12]
User[age=16]
User[age=23]
User[age=32]
User[age=43]

 

除此之外,还有另一种方法实现SortedSet集合排序:使用java.util.Comparator;来单独编写一个比较器,创建TreeSet集合的时候提供这个比较器,即SortedSet products=new TreeSet(new ProductComparator()); 代码如下:

 

import java.util.*;
public class SortedSetTest03{
 public static void main(String[] args){
   //创建TreeSet集合的时候提供一个比较器
   SortedSet products=new TreeSet(new ProductComparator());
   Product p1=new Product(3.4);
   Product p2=new Product(4.0);
   Product p3=new Product(3.6);
   Product p4=new Product(7.6);
   Product p5=new Product(3.7);
   
   products.add(p1);
   products.add(p2);
   products.add(p3);
   products.add(p4);
   products.add(p5);
   
   Iterator it=products.iterator();
   while(it.hasNext()){
     System.out.println(it.next());
     }
 }
}
class Product{
 double price;
 Product(double price){
   this.price=price;
 }
 public String toString(){
   return price + "";
 }
}
//单独编写一个比较器
class ProductComparator implements Comparator{
 //需求:按照商品价格排序
 public int compare(Object o1,Object o2){
   double price1=((Product)o1).price;
   double price2=((Product)o2).price;
   if (price1==price2){
     return 0;
   }else if(price1>price2){
     return -1;
   }
   return 1;
 }
}

 

编译运行后输出:

 

7.6
4.0
3.7
3.6
3.4

搜索微信公众号“程序员考拉”,欢迎关注!































































































































































































以上是关于Java关于一个java.util.TreeSet的问题的主要内容,如果未能解决你的问题,请参考以下文章

Java SortedSet为什么可以实现自动排序?

TreeSet

求一个关于JAVA的论文

Java基础7:关于Java类和包的那些事

关于JAVA线程的学习

关于Java-枚举的总结