TreeSet 今天郁闷了,一个哥们在看视频教学,问了我一个看似简单,却又答不出来的代码! 1:import java.util.TreeSet; 2: public class Demo8{ 3: public static void main(String[] args){ 4: TreeSet ts=new TreeSet(); 5: ts.add(new stu()); 7: } 8: } 10:class stu{} 期初我一看,这代码没问题,可以运行,MyEclipes 也没报错,但我错了!!到底哪里错了呢? 总是会出现(java.lang.ClassCastException);(运行环境JDK1.7) 我只存了一个对象,也类型转换了? 这样10行代码尽然花了我几个小时的时间才弄明白是什么回事!!我觉得也值得了。 所以把几个小时的时间总结了出来。 1.处理方式(加泛型) 说明:既然是(类型转换异常),那加上泛型指定该集合只能存储指定类型元素,应该就不会转换了吧? 带着疑问我把4行代码该成了: 4: TreeSet<stu> ts=new TreeSet<stu>(); 编译结果:PASS。 运行结果:类型转换异常(java.lang.ClassCastException) 分析:为什么呢?加了泛型,它在内部也转换了类型?又是茫茫多的疑问。。。。。。。 难道是自定义类出了什么问题?? 2.试探(存入一个java对外提供的常用类型String对象) 说明:如果常用类对象可以存储进TreeSet集合,那么肯定是自定义少写某些关键代码。 1:import java.util.TreeSet; 2: public class Demo8{ 3: public static void main(String[] args){ 4: TreeSet ts=new TreeSet(); 5: ts.add(new String(“abc”)); 7: } 8: } 10:class stu{} 编译结果:PASS。 运行结果:PASS。 真的是自定义类出了问题!到底是自定义类少了哪一部分?连一个元素都存不进去? 然后我依次将几个基本包装类都 单独 存了一遍,也没问题。 最后 单独 存了一个上帝,Object!!意外发生了!! 编译结果:PASS。 运行结果:类型转换异常(java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.Comparable) TreeSet到底是个什么集合,连上帝都拒绝进入,要满足什么条件才能进入呢? 根据错误提示,查阅了API文档发现这几个类都有个共同的方法(compareTo),而Object和我的自定义类都没有这个方法。(PC:^o^原来这就是问题的根本) 3.实现接口(Comparable重写其方法compareTo()) 1:import java.util.TreeSet; 2: public class Demo8{ 3: public static void main(String[] args){ 4: TreeSet ts=new TreeSet(); 5: ts.add(new stu()); 7: } 8: } 10:class stu implements Comparable{ 12: public int compareTo(T o){ 13: Return 1; 14: } 15:} 将代码改成这样后再运行! 编译结果:PASS。 运行结果:PASS。 分析:为什么实现了一个接口后就不出现类型转换异常了?难道元素不转换了? 又是疑问茫茫多。。。。。。。。 不解释,直接看源码!!这个够果断!! (打开TreeSet的源码一看,哇塞,高手编译的呀,都很牛逼哄哄~~~~~) 源码部分: public boolean add(E e) { return m.put(e, PRESENT)==null; } PC:尽然调用了一个Map集合的Put方法,里面肯定有一个Map集合 M.put(E e,Object obj)的一部分 public V put(K key, V value) { //传进一个键,值, Entry<K,V> t = root; if (t == null) { compare(key, key); // type (and possibly null) check root = new Entry<>(key, value, null); size = 1; modCount++; return null; } ....... Compare() final int compare(Object k1, Object k2) { Return comparator==null?((Comparable<?super K>)k1).compareTo((K)k2):comparator.compare((K)k1, (K)k2); } 终于找到答案了!! 1:import java.util.TreeSet; 2: public class Demo8{ 3: public static void main(String[] args){ 4: TreeSet ts=new TreeSet(); 5: ts.add(new String(“abc”)); 7: } 8: } 10:class stu{} //与Comparable没有任何关系 public class Object//与Comparable也没有任何关系 (Comparable<?super K>)k1尽然默认将我的自定义类强制转换成Comparable 难怪会出现(classCastException) 总结: 1.TreeSet集合与TreeMap集合只能存放实现了Comparable接口的同一类元素或者这一类元素的子类; (PC:严格来说只允许存储同一种类型的元素) 2.TreeSet集合内部有个TreeMap集合,调用TreeSet集合的add(E e)方法就是在调用TreeMap集合 的put(E e,Object obj)方法。(类似包装类) 3.当TreeSet集合没有任何元素,第一次添加元素时,它也会进行一次比较,自己与自己比较一次,但是不接受返回值。(PC:也就是说第一次比较肯定是返回0,但是没有对该值进行任何处理)。 题外话(TreeMap集合的二叉树存储尽然是自己的静态内部类完成的,惊讶了~~~~原来TreeMap也是个包装)
|