关闭 x
IT技术网
    技 采 号
    ITJS.cn - 技术改变世界
    • 实用工具
    • 菜鸟教程
    IT采购网 中国存储网 科技号 CIO智库

    IT技术网

    IT采购网
    • 首页
    • 行业资讯
    • 系统运维
      • 操作系统
        • Windows
        • Linux
        • Mac OS
      • 数据库
        • MySQL
        • Oracle
        • SQL Server
      • 网站建设
    • 人工智能
    • 半导体芯片
    • 笔记本电脑
    • 智能手机
    • 智能汽车
    • 编程语言
    IT技术网 - ITJS.CN
    首页 » JAVA »Java 容器和泛型(3)HashSet,TreeSet 和 LinkedHashSet比较

    Java 容器和泛型(3)HashSet,TreeSet 和 LinkedHashSet比较

    2015-04-08 00:00:00 出处:泥沙砖瓦浆木匠-Jeff_Li
    分享

    一、Set回顾

    一个不包括重复元素(包括可变对象)的Collection,是一种无序的集合。Set不包含满 a.equals(b) 的元素对a和b,并且最多有一个null。

    泥瓦匠的记忆宫殿:

    1、不允许包含相同元素

    2、判断对象是否相同,根据equals方法

    Java 容器 & 泛型:三、HashSet,TreeSet 和 LinkedHashSet比较

    二、HashSet

    一个按着Hash算法来存储集合中的元素,其元素值可以是NULL。它不能保证元素的排列顺序。同样,HashSet是不同步的,如果需要多线程访问它的话,可以用 Collections.synchronizedSet 方法来包装它:

    Set s = Collections.synchronizedSet(new HashSet(...));
    同上一节一样,用迭代器的时候,也要注意 并发修改异常ConcurrentModificationException。

    要注意的地方是,HashSet集合判断两个元素相等不单单是equals方法,并且必须hashCode()方法返回值也要相等。看下面的例子:

    import java.util.HashSet;
    
    class EuqalsObj
    {
        public boolean equals(Object obj)
        {
            return true;
        }
    }
    
    class HashCodeObj
    {
        public int hashCode()
        {
            return 1;
        }
    }
    
    class HashSetObj
    {
        public int hashCode()
        {
            return 2;
        }
    
        public boolean equals(Object obj)
        {
            return true;
        }
    }
    
    public class HashSetTest
    {
        public static void main(String[] args)
        {
            HashSet objs = new HashSet();
            objs.add(new EuqalsObj());
            objs.add(new EuqalsObj());
            objs.add(new HashCodeObj());
            objs.add(new HashCodeObj());
            objs.add(new HashSetObj());
            objs.add(new HashSetObj());
    
            System.out.println("HashSet Elements:");
            System.out.print("/t" + objs + "/n");
        }
    }

    Run 一下,控制台如下输出:

    HashSet Elements:
        [HashCodeObj@1, HashCodeObj@1, HashSetObj@2, EuqalsObj@1471cb25, EuqalsObj@3acff49f]

    泥瓦匠根据结果,一一到来。首先,排列顺序不定。

    HashSetObj 类满足我们刚刚的要求,所以集合中只有一个且它的HashCode值为2。

    HashCodeObj 类虽然它们HashCode值为1,但是他们不相等。(其实当HashCode值一样,这个存储位置会采用链式结构保存两个HashCodeObj对象。)

    同样,EqualsObj 类他们相等,但是他们HashCode值不等,分别为1471cb25、3acff49f。

    因此,用HashSet添加可变对象,要注意当对象有可能修改后和其他对象矛盾,这样我们无法从HashSet找到准确我们需要的对象。

    三、LinkedHashList

    HashSet的子类,也同样有HashCode值来决定元素位置。但是它使用链表维护元素的次序。记住两个字:有序。

    有序的妙用,复制。比如泥瓦匠实现一个HashSet无序添加,然后复制一个一样次序的HashSet来。代码如下:

    package com.sedion.bysocket.collection;
    
    import java.util.HashSet;
    import java.util.LinkedHashSet;
    import java.util.Set;
    
    public class LinkedHashListTest
    {
        public static void main(String[] args)
        {
            /* 复制HashSet */
            Set h1 = new HashSet<String>();
            h1.add("List");
            h1.add("Queue");
            h1.add("Set");
            h1.add("Map");
    
            System.out.println("HashSet Elements:");
            System.out.print("/t" + h1 + "/n");
    
            Set h2 = copy(h1);
            System.out.println("HashSet Elements After Copy:");
            System.out.print("/t" + h2 + "/n");
        }
    
        @SuppressWarnings({ "rawtypes", "unchecked" })
        public static Set copy(Set set)
        {
            Set setCopy = new LinkedHashSet(set);
            return setCopy;
        }
    
    }

    Run 一下,控制台输出:

    HashSet Elements:
        [Map, Queue, Set, List]
    HashSet Elements After Copy:
        [Map, Queue, Set, List]

    可见,每个数据结构都有它存在的理由。

    四、TreeSet

    TreeSet使用树结构实现(红黑树),集合中的元素进行排序,但是添加、删除和包含的算法复杂度为O(log(n))。

    举个例子吧,首先我们定义一个Bird类。(鸟是泥瓦匠最喜欢的动物)

    class Bird
    {
        int size;
    
        public Bird(int s)
        {
            size = s;
        }
    
        public String toString()
        {
            return size + "";
        }
    
    }

    然后用TreeSet添加Bird类。

    public class TreeSetTest
    {
        public static void main(String[] args)
        {
            TreeSet<Bird> bSet = new TreeSet<Bird>();
            bSet.add(new Bird(1));
            bSet.add(new Bird(3));
            bSet.add(new Bird(2));
    
            Iterator<Bird> iter = bSet.iterator();
    
            while (iter.hasNext())
            {
                Bird bird = (Bird) iter.next();
                System.out.println(bird);
            }
        }
    }

    Run一下,控制台输出如下:

    Exception in thread "main" java.lang.ClassCastException: Bird 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 com.sedion.bysocket.collection.TreeSetTest.main(TreeSetTest.java:29)

    答案很明显,TreeSet是排序的。所以Bird需要实现Comparable此接口。

    java.lang.Comparable此接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo 方法被称为它的自然比较方法。

    修改Bird如下:

    class Bird implements Comparable<Bird>
    {
        int size;
    
        public Bird(int s)
        {
            size = s;
        }
    
        public String toString()
        {
            return size + "号鸟";
        }
    
        @Override
        public int compareTo(Bird o)
        {
            return size - o.size;
        }
    
    }

    再次Run一下:

    1号鸟
    2号鸟
    3号鸟

    五、性能测试比较

    针对上面三种Set集合,我们对它们的Add方法进行性能测试:

    import java.util.HashSet;
    import java.util.LinkedHashSet;
    import java.util.Random;
    import java.util.TreeSet;
    
    class Bird implements Comparable<Bird>
    {
        int size;
    
        public Bird(int s)
        {
            size = s;
        }
    
        public String toString()
        {
            return size + "号鸟";
        }
    
        @Override
        public int compareTo(Bird o)
        {
            return size - o.size;
        }
    
    }
    public class Set
    {
        public static void main(String[] args)
        {
            Random r = new Random();
    
            HashSet<Bird> hashSet = new HashSet<Bird>();
            TreeSet<Bird> treeSet = new TreeSet<Bird>();
            LinkedHashSet<Bird> linkedSet = new LinkedHashSet<Bird>();
    
            // start time
            long startTime = System.nanoTime();
    
            for (int i = 0; i < 1000; i++) {
                int x = r.nextInt(1000 - 10) + 10;
                hashSet.add(new Bird(x));
            }
            // end time
            long endTime = System.nanoTime();
            long duration = endTime - startTime;
            System.out.println("HashSet: " + duration);
    
            // start time
            startTime = System.nanoTime();
            for (int i = 0; i < 1000; i++) {
                int x = r.nextInt(1000 - 10) + 10;
                treeSet.add(new Bird(x));
            }
            // end time
            endTime = System.nanoTime();
            duration = endTime - startTime;
            System.out.println("TreeSet: " + duration);
    
            // start time
            startTime = System.nanoTime();
            for (int i = 0; i < 1000; i++) {
                int x = r.nextInt(1000 - 10) + 10;
                linkedSet.add(new Bird(x));
            }
            // end time
            endTime = System.nanoTime();
            duration = endTime - startTime;
            System.out.println("LinkedHashSet: " + duration);
        }
    }

    Run一下,可以在控制台中看出:

    HashSet: 2610998
    TreeSet: 3195378
    LinkedHashSet: 2673782

    可见,TreeSet因为需要进行比较,所以性能比较差。

    六、总结

    HashSet:equlas hashcode

    LinkedHashSet:链式结构

    TreeSet:比较,Comparable接口,性能较差

    上一篇返回首页 下一篇

    声明: 此文观点不代表本站立场;转载务必保留本文链接;版权疑问请联系我们。

    别人在看

    Edge浏览器百度被劫持/篡改怎么办,地址后边跟着尾巴#tn=68018901_7_oem_dg

    Google Chrome 在 iPhone 上新增了 Safari 数据导入选项

    Windows 11专业版 KMS工具激活产品密钥的方法

    DEDECMS安全策略官方出品

    Microsoft Text Input Application 可以关闭吗?

    新版本QQ如何关闭自带的浏览器?

    C++编程语言中continue的用法和功能,附举例示范代码

    c++ map 的数据结构、基本操作以及其在实际应用中的使用。

    C语言如何避免内存泄漏、缓冲区溢出、空指针解引用等常见的安全问题

    C语言中的break语句详解

    IT头条

    马斯克2026最新采访总结:2040年,全球机器人数量将突破100亿台

    23:52

    专家解读|规范人工智能前沿业态健康发展的新探索:解读《人工智能拟人化互动服务管理暂行办法》

    00:54

    用至强 6高存力搞定MoE卸载!

    17:53

    美国将允许英伟达向中国“经批准的客户”出售H200 GPU

    02:08

    苹果与微信就15%手续费达成一致?腾讯未置可否

    22:00

    技术热点

    PHP 和 Node.js 的10项对比挑战

    Javascript闭包深入解析及实现方法

    windows 7、windows 8.1手动增加右键菜单功能技巧

    MYSQL出错代码大汇总

    windows 7假死机怎么办 windows 7系统假死机的原因以及解决方法

    Ubuntu(Linux)下配置IP地址的方法

      友情链接:
    • IT采购网
    • 科技号
    • 中国存储网
    • 存储网
    • 半导体联盟
    • 医疗软件网
    • 软件中国
    • ITbrand
    • 采购中国
    • CIO智库
    • 考研题库
    • 法务网
    • AI工具网
    • 电子芯片网
    • 安全库
    • 隐私保护
    • 版权申明
    • 联系我们
    IT技术网 版权所有 © 2020-2025,京ICP备14047533号-20,Power by OK设计网

    在上方输入关键词后,回车键 开始搜索。Esc键 取消该搜索窗口。