Java中的Map集合框架

系列文章目录

Java中的Set集合框架
Java中的List集合框架


前言

本文介绍了Java中常用的集合框架HashMap,本文为系列文章也是本系列最后一篇,如果喜欢的话,可以点赞,收藏,关注。


一、Map

1.Map类型的特点

Java中的Map是一种接口类型,它定义了一种将键映射到值的数据结构。Map中的元素是通过键值对来存储和访问的。以下是Map类型的主要特点:

  1. 键的唯一性:在Map中,每个键只能对应一个值。如果尝试使用相同的键插入多个值,那么后续的插入操作将覆盖先前的值。
  2. 键和值的存储:Map中的键和值可以是任何类型的对象,包括自定义的对象类型。键和值的存储是相互独立的,即键的类型与值的类型可以是不同的类型。
  3. 键的有序性:在Java中,Map的内部实现有多种方式,如HashMap、LinkedHashMap等。不同的实现方式对键的存储顺序可能会有所不同。例如,HashMap不保证键的顺序,而LinkedHashMap则按照键的插入顺序进行排序。
  4. Map的遍历:可以通过迭代器(Iterator)来遍历Map中的所有元素。遍历时,元素的顺序可能与插入顺序不同,具体取决于Map的实现方式。
  5. Map的操作:Map提供了一些常用的操作方法,如put(key, value)用于插入或更新元素,get(key)用于根据键获取对应的值,remove(key)用于删除指定键对应的元素等。
  6. Map的实现类:Java提供了多个Map的实现类,如HashMap、LinkedHashMap、TreeMap等。这些实现类具有不同的特点和用途,可以根据实际需求选择合适的实现方式。

2.HashMap基本实现原理

  1. 数据存储:HashMap内部采用数组+链表(Java 8后为数组+树)的方式存储数据。数组是HashMap的基础,每个数组元素就是一个Node对象,包含三个部分:key、value和next指针。
  2. 散列映射:当我们将键值对存入HashMap时,首先会对键进行散列(hash)操作,得到一个散列值,这个散列值对应数组的某个位置,然后将该键值对存入该位置的Node中。
  3. 解决冲突:由于不同的键可能会得到相同的散列值,因此可能会产生冲突。HashMap通过链表的方式解决这个问题。当两个或多个键得到相同的散列值时,它们会被存放在同一个链表中。在查询时,如果根据key得到的散列值相同,就会在对应的链表中按照next指针顺序查找。
  4. 树的构建(Java 8及以后版本): 当链表的长度大于一定阈值(默认为8)时,会将链表转换为红黑树(一种自平衡的二叉搜索树)。树的节点数总是大于等于链表的节点数,所以查找、插入、删除在树上的操作时间复杂度是O(log n)。
  5. 树的合并(Java 8及以后版本): 当红黑树的节点数小于等于6时,会将红黑树转回为链表。

3.HashMap案例

public class HashMapTest {
    public static void main(String[] args) {
        //双列,键值结构
        //key不可重复,value可重复
        Map hashMap = new HashMap<>();
        hashMap.put("a", "注意看这个");
        hashMap.put("b", "桃子");
        hashMap.put("c", "梨");
        hashMap.put("d", "芒果");
        hashMap.put("a", "被修改了");//修改
        System.out.println("长度为:"+hashMap.size());
        //拿到hashMap中所有的key
        Set set = hashMap.keySet();
        for (Object o : set) {
            System.out.println(o+":"+hashMap.get(o));
        }
    }
}

/**
长度为:4
a:被修改了
b:桃子
c:梨
d:芒果
*/

因为Set是无序的,取到的key也是无序的,所以打印出来也是无序的

4.Map常用方法

在这里插入图片描述

代码示例:

public class HashMapTest {
    public static void main(String[] args) {
        Map hashMap = new HashMap<>();
        hashMap.put("a", "注意看这个");
        hashMap.put("b", "桃子");
        hashMap.put("c", "梨");
        hashMap.put("d", "芒果");
        hashMap.put("a", "被修改了");
        System.out.println("长度为:"+hashMap.size());//获取长度
        System.out.println(hashMap.get("a"));//通过key取value
        System.out.println(hashMap.containsKey("b"));//查询hashMap中是否存在某个键
        System.out.println(hashMap.remove("c"));//移除键,返回对应的value
        System.out.println(hashMap.keySet());//返回一个存有key的set
        System.out.println(hashMap.values());//返回一个存有value的collection
        hashMap.clear();//清空hashMap
        System.out.println("长度为:"+hashMap.size());
    }
}
/**
长度为:4
被修改了
true
梨
[a, b, d]
[被修改了, 桃子, 芒果]
长度为:0
*/

二、泛型在集合中的应用

1.为什么使用泛型

在上述代码例子中,key和value可以添加任意数据类型的值,会出现一些类型不匹配和强制类型转换的问题。

使用泛型还可以提高代码的灵活性和可重用性。假设我们有一个程序需要处理不同类型的数据,如果使用Object类型的键和值,则需要使用强制类型转换来获取具体类型的对象。而使用泛型,我们可以在定义List,Set,Map集合时指定具体的类型,使得代码更加清晰和易于维护。

代码示例(以List举例,未使用泛型):

public class GenericTest {
    public static void main(String[] args) {
        List list=new ArrayList();
        list.add(new Dog("a","a"));
        list.add(1);
        list.add("test");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
    }
}
/**
Dog{name='a', type='a'}
1
test
*/

代码可读性极低,当数据量极大时,需要取list中Dog类型的数据进行操作,需要先使用到instanceof关键字判断是否为Dog类型,然后再进行操作

2.泛型入门

public class GenericTest<T> {
    T a;

    public void show(T a) {
        System.out.println(a);
    }

    public static void main(String[] args) {
        GenericTest objectGenericTest = new GenericTest();
        objectGenericTest.show("a");
        objectGenericTest.show(123);
    }
}

使用泛型可以传入不同数据类型的数据,也可以指定传入的数据类型。

指定传入的数据类型

public class GenericTest<T> {
    T a;

    public void show(T a) {
        System.out.println(a);
    }

    public static void main(String[] args) {
        GenericTest<String> objectGenericTest = new GenericTest<String>();
        objectGenericTest.show("a");
    }
}

指定传入的数据类型不能是基础数据类型,比如指定传入整型,就只能使用int类型的包装类型Integer

3.在Map中使用泛型

在代码中插入一条非String类型的数据

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TNi59Zjw-1692193811557)(./Java中的集合框架.assets/image-20230816180556484.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PfKIjIa1-1692193811558)(./Java中的集合框架.assets/image-20230816180625776.png)]

所以,在使用泛型时申明了传入的数据类型,便只能传入对应的类型。

提示

Map<String, String> hashMap = new HashMap<String, String>();//后面的那个<>可以省略
Map<String, String> hashMap = new HashMap();//可以写成这样,但是只能是jdk6以上的版本才能省略

补充

迭代器Iterator

==增强型for循环(语法糖)==的底层都是靠迭代器实现,其原理大致为:

  1. 对于数组:增强for循环会隐式地创建一个ArrayIterator,该ArrayIterator负责遍历数组并返回数组的每个元素。对于基本类型的数组,这个ArrayIterator是类型特定的,即每个类型都会有一个对应的ArrayIterator类。
  2. 对于集合(Collection):增强for循环会隐式地创建一个迭代器,该迭代器会遍历集合并返回集合的每个元素。对于实现了Iterable接口的集合类(如List,Set等),增强for循环可以直接使用Iterable接口的iterator方法获取一个迭代器。
extends
extends
implements
extends
HashSet
AbstractSet
AbstractCollection
Collection
Iterable

在这里插入图片描述

Iterator使用案例

public class IteratorTest {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<Integer>();
        set.add(1);set.add(2);set.add(3);set.add(4);
        Iterator<Integer> iterator = set.iterator();
        while (iterator.hasNext()) {//判断是否存在下一个值
            System.out.println(iterator.next());//获取迭代器中的下一个元素
        }
    }
}
/*
1
2
3
4
**/

Collections集合框架工具类

public class CollectionsUtilTest {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        for (int i = 0; i <= 54; i++) {
            list.add(i);//生成了一个0到54的列表
        }
        System.out.println(list);//列表初始状态
        Collections.addAll(list,55,56);//追加元素
        System.out.println(list);
        Collections.reverse(list);//将整个列表反向
        System.out.println(list);
        Collections.shuffle(list);//类似洗牌的操作,将整个列表打乱
        System.out.println(list);
    }
}

本节主要介绍了三个工具方法,主要用于列表中的操作,更多方法可以查看官方文档,搜索Collections。

总结

  Java中的Map接口为开发人员提供了方便而强大的数据结构,可以有效地存储和操作键值对数据。它的特性使得Map在开发中具有重要的影响,可以简化数据操作,提高代码的可读性和可维护性。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

笑的像个child

好人一生平安,先磕为敬

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值