A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© Tking 中级黑马   /  2014-4-5 21:04  /  1033 人查看  /  0 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

TreeSet
今天郁闷了,一个哥们在看视频教学,问了我一个看似简单,却又答不出来的代码!
1import 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集合,那么肯定是自定义少写某些关键代码。
1import 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())
1import 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.putE eObject 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);
}
终于找到答案了!!
1import 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集合的addE e)方法就是在调用TreeMap集合
putE eObject obj)方法。(类似包装类)
3.TreeSet集合没有任何元素,第一次添加元素时,它也会进行一次比较,自己与自己比较一次,但是不接受返回值。(PC:也就是说第一次比较肯定是返回0,但是没有对该值进行任何处理)。
题外话(TreeMap集合的二叉树存储尽然是自己的静态内部类完成的,惊讶了~~~~原来TreeMap也是个包装)

评分

参与人数 1技术分 +1 收起 理由
菜小徐 + 1

查看全部评分

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马