当前位置:

首页 > 编程开发 > 如何在Java中实现集合?

如何在Java中实现集合?

1、HashMappublicclassHashMapDemo{privateMapmap=null;publicvoidinit(){map=newHashMap();map.put("a","aaa");map.put("b","bbb");map.put("c","ccc");System.out.println(map);}//添加元素publicvoidtestPut(){//Vput(Kkey,Vvalue):把指定的key和value添加到集合中map.put("a1","aaa");map

本文目录

    1、HashMap

    public class HashMapDemo {
        private Map map = null;
        public void init() {
            map = new HashMap();
            map.put("a", "aaa");
            map.put("b", "bbb");
            map.put("c", "ccc");
            System.out.println(map);
        }
        // 添加元素
        public void testPut() {
            // V put(K key, V value) :把指定的key和value添加到集合中
            map.put("a1", "aaa");
            map.put("b1", "bbb");
            map.put("c1", "ccc");
            System.out.println(map);
            // void putAll(Mapm) :把指定集合添加集合中
            Map map1 = new HashMap();
            map1.put("e", "eee");
            map1.put("f", "fff");
            map.putAll(map1);
            System.out.println(map);
            // default V putIfAbsent(K key, V value) :如果key不存在就添加
            map.putIfAbsent("a", "hello");
            System.out.println(map);
            map.putIfAbsent("g", "ggg");
            System.out.println(map);
        }
        // 修改元素
        public void testModify() {
            // V put(K key, V value) :把集合中指定key的值修改为指定的值
            map.put("a", "hello");
            map.put("a", "world");
            System.out.println(map);
            // 说明,当key相同时,后面的值会覆盖前面的值。
            // default V replace(K key, V value) :根据key来替换值,而不做增加操作
            Object replace = map.replace("b1", "java");
            System.out.println(replace);
            System.out.println(map);
            //default boolean replace(K key, V oldValue,V newValue)
        }
        // 删除元素
        public void testRemove() {
            // V remove(Object key) :根据指定key删除集合中对应的值
            Object c = map.remove("c");
            System.out.println(c);
            System.out.println(map);
            // default boolean remove(Object key, Objectvalue) :根据key和value进行删除
            map.remove("b", "bbb1");
            System.out.println(map);
            // void clear() :清空集合中所有元素
            map.clear();
            System.out.println(map);
        }
        // 判断元素
        public void testJudge() {
            // boolean isEmpty() :判断集合是否为空,如果是返回true,否则返回false
            System.out.println(map.isEmpty());
            // boolean containsKey(Object key) :判断集合中是否包含指定的key,包含返回true,否则返回false
            boolean flag = map.containsKey("a");
            System.out.println(flag); // true
            flag = map.containsKey("a1");
            System.out.println(flag); // false
            // boolean containsValue(Object value) :判断集合中是否包含指定的value,包含返回true,否则返回false
            flag = map.containsValue("aaa");
            System.out.println(flag); // true
            flag = map.containsValue("aaa1");
            System.out.println(flag); // false
        }
        // 获取元素
        public void testGet() {
            // int size() :返回集合的元素个数
            int size = map.size();
            System.out.println(size);
            // V get(Object key) :根据Key获取值,如果找到就返回对应的值,否则返回null
            Object val = map.get("a");
            System.out.println(val);
            val = map.get("a1");
            System.out.println(val); // null
            // default V getOrDefault(Object key, VdefaultValue) :根据Key获取值,如果key不存在,则返回默认值
            val = map.getOrDefault("a1", "hello");
            System.out.println(val);
            // Collection values() :返回集合中所有的Value
            Collection values = map.values();
            for (Object value : values) {
                System.out.println(value);
            }
            // Set keySet() :返回集合中所有的Key
            Set set = map.keySet();
            for (Object o : set) {
                System.out.println(o);
            }
        }
        // 迭代元素
        public void testIterator() {
            // 第一种:通过key获取值的方式
            Set keySet = map.keySet();
            Iterator it = keySet.iterator();
            while (it.hasNext()) {
                Object key = it.next();
                Object val = map.get(key);
                System.out.println(key + "=" + val);
            }
            System.out.println("------------------------ ");
            // 第二种:使用for循环
            for (Object key : map.keySet()) {
                System.out.println(key + "=" +
                                   map.get(key));
            }
            System.out.println("------------------------ ");
            // 第三种:使用Map接口中的内部类来完成,在框架中大量使用
            Set entrySet = map.entrySet();
            for (Object obj : entrySet) {
                Map.Entry entry = (Map.Entry) obj;
                System.out.println(entry.getKey() + "=" +
                                   entry.getValue());
            }
        }
    }

    说明:在HashMap中键-值允许为空,但键唯一,值可重复。hashMap不是线程安全的。

    2、TreeMap

    是一个有序的集合,默认使用的是自然排序方式。

    public class Person implements Comparable {
        private String name;
        private int age;
        @Override
        public int compareTo(Object o) {
        if (o instanceof Person) {
        Person p = (Person) o;
        return this.age - p.age;
        }
        return 0;
    }
        public Person() {}
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        @Override
        public String toString() {
            return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
        }
    }

    测试

    public class TeeMapDemo {
        @Test
        public void testInteger() {
            TreeMap tm = new TreeMap();
            tm.put(3, 333);
            tm.put(2, 222);
            tm.put(11, 111);
            tm.put(2, 222);
            System.out.println(tm);
        }
        @Test
        public void testString() {
            TreeMap tm = new TreeMap();
            tm.put("hello", "hello");
            tm.put("world", "world");
            tm.put("about", "");
            tm.put("abstract", "");
            System.out.println(tm);
        }
        @Test
        public void testPerson() {
            TreeMap tm = new TreeMap(new Comparator(){
                @Override
                public int compare(Object o1, Object o2) {
                    if (o1 instanceof Person && o2
                        instanceof Person) {
                        Person p1 = (Person) o1;
                        Person p2 = (Person) o2;
                        return p1.getAge() - p2.getAge();
                    }
                    return 0;
                }
            });
            tm.put(new Person("张三",18), null);
            tm.put(new Person("李四",17), null);
            System.out.println(tm);
        }
    }

    说明:从上面的代码可以发现,TreeMap的使用和TreeSet的使用非常相似,观察HashSet集合的源代码可以看出,当创建 HashSet集合时,其实是底层使用的是HashMap。

    public HashSet() {
    	map = new HashMap<>();
    }

    HashSet实际上存的是HashMap的Key。

    3.ConcurrentHashMap

    在Map集合中我们介绍了HashMap,TreeMap,在多线程的情况下这些集合都不是线程安全的,因此可能出现线程安全的问题。

    在Java中Hashtable是一种线程安全的HashMap,Hashtable在方法上与HashMap并无区别,仅仅只是在方法使用了synchronized以此来达到线程安全的目的,我们观察Hashtable的源码。

    public synchronized V get(Object key) {
            Entry tab[] = table;
            int hash = key.hashCode();
            int index = (hash & 0x7FFFFFFF) % tab.length;
            for (Entry e = tab[index] ; e != null ; e = e.next) {
                if ((e.hash == hash) && e.key.equals(key)) {
                    return (V)e.value;
                }
            }
            return null;
        }

    以上是Hashtable的get源码,可以看出它仅仅只是在方法上添加了锁,这大大降低了线程的执行效率,以牺牲效率的形式来达到目的,这显然不是我们在实际中想要的,因此我们需要一种既能在线程安全方面有保障,在效率上还可以的方法。

    ConcurrentHashMap采用的是分段锁的原理,我们观察源码。

     public V put(K key, V value) {
            return putVal(key, value, false);
        }
    final V putVal(K key, V value, boolean onlyIfAbsent) {
            if (key == null || value == null) throw new NullPointerException();
            int hash = spread(key.hashCode());
            int binCount = 0;
            for (Node[] tab = table;;) {
                Node f; int n, i, fh;
                if (tab == null || (n = tab.length) == 0)
                    tab = initTable();
                else if ((f = tabAt(tab, i = (n - 1) & hash)) == null) {
                    if (casTabAt(tab, i, null,
                                 new Node(hash, key, value, null)))
                        break;                   // no lock when adding to empty bin
                }
                else if ((fh = f.hash) == MOVED)
                    tab = helpTransfer(tab, f);
                else {
                    V oldVal = null;
                    synchronized (f) {
                        if (tabAt(tab, i) == f) {
                            if (fh >= 0) {
                                binCount = 1;
                                for (Node e = f;; ++binCount) {
                                    K ek;
                                    if (e.hash == hash &&
                                        ((ek = e.key) == key ||
                                         (ek != null && key.equals(ek)))) {
                                        oldVal = e.val;
                                        if (!onlyIfAbsent)
                                            e.val = value;
                                        break;
                                    }
                                    Node pred = e;
                                    if ((e = e.next) == null) {
                                        pred.next = new Node(hash, key,
                                                                  value, null);
                                        break;
                                    }
                                }
                            }
                            else if (f instanceof TreeBin) {
                                Node p;
                                binCount = 2;
                                if ((p = ((TreeBin)f).putTreeVal(hash, key,
                                                               value)) != null) {
                                    oldVal = p.val;
                                    if (!onlyIfAbsent)
                                        p.val = value;
                                }
                            }
                        }
                    }
                    if (binCount != 0) {
                        if (binCount >= TREEIFY_THRESHOLD)
                            treeifyBin(tab, i);
                        if (oldVal != null)
                            return oldVal;
                        break;
                    }
                }
            }
            addCount(1L, binCount);
            return null;
        }

    从源码中可以看出ConcurrentHashMap仅仅是在当有线程去操作当前数据的时候添加了锁,因此效率大大提高了。

    在线程安全的情况下提高了效率。

    本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
    作者最新文章
    编程开发 Java
    相关文章 更多
    Yandex官网入口及网页搜索使用方法
    Yandex官网入口及网页搜索使用方法

    Yandex官网入口是https://www.yondex.net/,该平台支持多语言切换、智能搜索匹配、虚拟键盘变更及实时翻译,提供地图、图片、新闻、购物等垂直服务,并具备账户同步、隐私管理、个性化首页和云存储等功能。

    Java单元测试入门:使用JUnit 5编写第一个测试用例
    Java单元测试入门:使用JUnit 5编写第一个测试用例

    面向初学者的JUnit 5实用入门指南。从测试概念、Maven依赖配置,到手把手编写首个单元测试用例及断言验证,助你掌握Java单元测试的核心流程。

    Java变量未初始化报错解析:局部变量与成员变量默认值差异
    Java变量未初始化报错解析:局部变量与成员变量默认值差异

    深入解析Java中局部变量未初始化编译报错与成员变量自动赋予默认值的机制差异,涵盖JVM内存分配、编译期确定性赋值检查与实际排查修复方案。

    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat
    Java获取当前时间并格式化输出:DateTimeFormatter与SimpleDateFormat

    详细讲解在Java中获取当前系统时间并进行格式化输出的两种核心方案:基于Java 8全新日期时间API的DateTimeFormatter与传统遗留的SimpleDateFormat,包含完整代码示例、线程安全机制对比及生产选型建议。

    Java中final与static final常量的定义及初始化规则
    Java中final与static final常量的定义及初始化规则

    深入解析Java中final变量与static final常量的定义、内存语义、初始化时机及合法赋值路径,涵盖编译期常量优化与实战避坑指南。

    Java抽象方法与接口方法的区别及选型建议
    Java抽象方法与接口方法的区别及选型建议

    深入对比Java中抽象类抽象方法与接口方法的语法演进、设计意图及运行期差异,并提供清晰的架构选型决策流程与实战范例。

    Java实现HTTP请求与JSON解析的完整代码示例
    Java实现HTTP请求与JSON解析的完整代码示例

    本文提供Java标准库HttpClient发起HTTP GET/POST请求并结合Jackson进行JSON数据反序列化与序列化的完整代码示例与工程实践指南。

    Java递归出现StackOverflowError的原因分析及栈空间优化方案
    Java递归出现StackOverflowError的原因分析及栈空间优化方案

    详细分析Java递归调用出现StackOverflowError的原因,结合代码说明线程栈、栈帧和递归深度之间的关系,并介绍终止条件排查、迭代改写、减少栈帧开销以及通过-Xss调整JVM栈空间的方法。

    Java空指针异常(NPE)的代码排查与修复实例
    Java空指针异常(NPE)的代码排查与修复实例

    针对Java中常见的NullPointerException(NPE),本文从堆栈日志定位、典型代码触发场景、具体修复代码对比到防御体系进行系统讲解,提供实用且易上手的排查与修复方案。

    selenium上传文件教程本地文件路径设置方法
    selenium上传文件教程本地文件路径设置方法

    深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

    查看更多
    精品专题 更多
    装机必备
    装机必备

    正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

    Windows
    Windows

    正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

    PDF教程
    PDF教程

    正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

    Mac软件 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    Aperty macOS版
    Aperty macOS版
    macOS

    Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

    WINDOWS 更多
    讯飞智作 网页版
    讯飞智作 网页版
    Windows/ macOS/ Linux

    讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

    火山引擎 网页版
    火山引擎 网页版
    Windows/ macOS/ Linux

    火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

    PixTV 网页版
    PixTV 网页版
    Windows

    PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。