集合 简单HashMap例子

本文深入探讨了Java中HashMap的工作原理及其应用场景。介绍了如何通过自定义User类来增强HashMap的功能,包括实现键值对的存储与检索。同时,还讲解了HashMap内部结构,如其如何通过哈希算法定位元素及解决冲突的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 

hash是无序的,不能排序,如果想要map能排序,就要使用TreeHash,它会根据键的字母顺序自动排序

HashMap就像一个数组,里面有16个位置可以存放数据,每个位置下面可以通过链表的方式存在各种数据

HashMap是键值对,通过键找到值,将键进行hashcode后,对hashcode后的值的进行%16,也就是0-15,然后找到键所在的数组位置,定位到键


如果在那个数组中后两个相同的键,前面的键会被后面的覆盖

 

1、写个User类,写个username和password变量,并对这两个变量进行getter、setter、toString、构造函数,不toString的话,用map调用时只能看见键的地址,无法看见内容

public class User {

    private String username;
    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }


    @Override
    public String toString() {
        return "User{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

2、map类

import java.util.HashMap;
import java.util.Map;

public class MapTest {

    @Test
    public void Test1(){
        Map<String,User> map = new HashMap<>();
        map.put("班长",new User("小马",null));
        map.put("学习委员",new User("小王",null));
        map.put("体育委员",new User("小白",null));
        map.put("卫生委员",new User("小男",null));
        map.put("副班长",new User("小画",null));

        // User中要toString,否则输入的是地址不是内容
        // HashMap通过键找到值,是将键进行hashcode后,对hashcode后的值的进行%16,然后找到键所在的数组位置,定位到键
        // 如果在那个数组中后两个相同的键,前面的键会被后面的覆盖
        System.out.println(map.get("学习委员"));

        // HashMap的遍历,死记硬背  hash不能排序,能根据Key排序的叫TreeMap,他会按字母顺序自动排序
        for (Map.Entry entry : map.entrySet()){
            System.out.println(entry.getKey());
            System.out.println(entry.getValue());
        }
    }
}

上面的遍历是先出来键,然后出来值。我们对map的遍历还可以使用其他的方法,下面的方法可以直接遍历出map的值。set是hash的父类,所以可以用。

Set<String> keys = map.keySet();
        for (String key : keys) {
            System.out.println(map.get(key));
        }

 

<think>嗯,用户让我介绍一下HashMap集合的特性,而且需要用中文回答。首先,我得回想一下HashMap的基本概念。HashMapJava中常用的数据结构,属于Map接口的一个实现类,对吧?它存储键值对,允许键和值都为null,而且是非同步的,线程不安全。 接下来,我应该组织一下结构,确保覆盖所有主要特性。比如,哈希表的结构,数组和链表(或者红黑树,在Java 8之后)的结合。然后是键的唯一性,如果重复的键插入,会覆盖旧值。还有,插入和查询的高效性,通常是O(1)时间复杂度,但在最坏情况下可能变成O(n),不过Java 8之后优化为红黑树,所以最坏情况是O(log n)。 还要提到哈希冲突的解决方式,即拉链法,每个数组元素是一个链表或树节点。另外,初始容量和负载因子,默认是16和0.75,当元素数量超过容量乘以负载因子时,会扩容两倍,并重新哈希。这可能影响性能,所以初始化时选择合适的容量和负载因子可以优化性能。 还有无序性,HashMap不保证元素的顺序,特别是Java 8之后,即使遍历顺序也可能变化。迭代的时候,使用entrySet、keySet或values来获取集合视图。线程不安全,如果在多线程环境下使用,可能会导致问题,需要用Collections.synchronizedMap或者ConcurrentHashMap来保证线程安全。 可能需要举个例子,比如如何插入、获取、删除键值对,以及如何处理null键和值的情况。还要指出为什么HashMap在查找和插入时高效,因为通过哈希函数直接定位到桶的位置,减少了遍历的次数。 有没有可能用户是刚开始学习Java集合框架,所以需要比较基础的讲解?或者他们可能已经有一定基础,想深入了解内部实现机制?可能需要平衡理论和实际使用,既讲特性,也讲应用场景和注意事项。 另外,注意区分不同版本的区别,比如Java 8之后的红黑树优化,避免给出过时的信息。比如在冲突严重时,链表转换为红黑树,提高查询效率。而容量总是2的幂,这样设计是为了哈希计算时更高效,用位运算代替取模运算。 还要提到key的hashCode和equals方法的重要性,如果两个key的hashCode相同但equals返回false,还是会冲突,这时候会存储在同一个桶的链表或树中。如果equals方法重写不正确,可能导致无法正确找到对应的键值对。 总结的时候,需要强调HashMap适合需要快速查找、插入、删除的场景,但不适合需要有序存储的情况,这时候可以用LinkedHashMap或者TreeMap。同时线程不安全的问题需要特别注意,多线程环境下的替代方案。 可能用户在实际使用中遇到性能问题,或者不了解为什么有时候HashMap效率下降,这时候解释负载因子和扩容机制就很重要了。或者他们可能遇到并发修改异常,需要提醒线程安全的问题。 总之,回答要全面但不过于冗长,结构清晰,分点列出特性,并适当解释原理和应用注意事项。确保用词准确,比如哈希冲突、拉链法、红黑树、负载因子等术语正确使用,同时用通俗的语言让读者容易理解。</think>**HashMap 集合的特性介绍** **HashMap** 是 Java 中基于哈希表实现的 `Map` 接口的常用类,具有以下核心特性: --- ### 1. **键值对存储** - 存储形式为 `Key-Value`(键值对),支持 `null` 作为键或值(但键唯一,仅允许一个 `null` 键)。 - 示例:`map.put("name", "Alice")`。 --- ### 2. **高效查找与插入** - **平均时间复杂度为 O(1)**:通过哈希函数将键(`Key`)映射到哈希表的桶(`bucket`)位置,直接定位数据。 - 性能受哈希函数质量、冲突处理方式影响。 --- ### 3. **哈希冲突与数据结构** - **拉链法解决冲突**:每个桶通过链表(Java 7)或链表+红黑树(Java 8+)存储冲突的键值对。 - **优化**:当链表长度超过阈值(默认8),链表转为红黑树,查询效率从 `O(n)` 提升至 `O(log n)`。 --- ### 4. **动态扩容机制** - **默认初始容量**:16,**负载因子**:0.75(当元素数量超过 `容量×负载因子` 时触发扩容)。 - 扩容时容量翻倍(如 16 → 32),并重新哈希所有键值对,可能影响性能。初始化时合理设置容量可减少扩容次数。 --- ### 5. **无序性与非线程安全** - **不保证顺序**:插入顺序、自然顺序均不保证。若需有序,可使用 `LinkedHashMap` 或 `TreeMap`。 - **非线程安全**:多线程并发修改可能导致数据不一致,需通过 `ConcurrentHashMap` 或同步包装类(如 `Collections.synchronizedMap()`)实现线程安全。 --- ### 6. **依赖 hashCode() 和 equals()** - **键的唯一性**:通过 `hashCode()` 确定存储位置,`equals()` 判断键是否重复。 - **重写要求**:若自定义对象作为键,需正确重写 `hashCode()` 和 `equals()` 方法,否则可能导致逻辑错误。 --- ### 7. **允许 null 键/值** - 可存储一个 `null` 键和多个 `null` 值,但需注意操作时的空指针问题。 --- ### **应用场景** - 快速查询、插入、删除(如缓存、索引)。 - 不涉及多线程或已处理同步问题的场景。 --- ### **示例代码** ```java HashMap<String, Integer> map = new HashMap<>(); map.put("apple", 10); // 插入 map.get("apple"); // 返回 10 map.remove("apple"); // 删除 ``` --- **总结**:HashMap 以空间换时间,适合高效键值操作,但需注意哈希函数设计、扩容开销及线程安全问题。理解其底层机制(如哈希表、红黑树)有助于优化使用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值