map集合转换为object思想

这篇博客介绍了在MyBatis中如何将查询结果的Map集合转换为实体对象集合,通过创建实体对象并进行测试,展示了转换的具体思路。

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

1.创建实体对象

public class User {
    private String name;
    private String pass;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPass() {
        return pass;
    }

    public void setPass(String pass) {
        this.pass = pass;
    }

    /**
     * 转换
     * @param data
     */
    public User(Map<String, Object> data) {
        this.name = data.get("name").toString();
        this.pass = data.get("pass").toString();
    }

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

2.测试

public class Test {
    public static void main(String[] args) {
        List<Map<String, Object>> lists = getStringObjectMap();
        List<User> users = zhuanhuan(lists);
        out(users);
    }


    /**
     * 打印
     * @param users
     */
    private static void out(List<User> users) {
        for (User user : users) {
            System.out.println(user);
        }
    }

    /**
     * 构造一个map集合
     * @return
     */
    private static List<Map<String, Object>> getStringObjectMap() {
        List<Map<String,Object>> lists = new ArrayList<>();
        Map<String,Object> map1  = new HashMap<>();
        map1.put("name","zhengke1");
        map1.put("pass","123456");
        Map<String,Object> map2  = new HashMap<>();
        map2.put("name","zhengke2");
        map2.put("pass","123456");
        lists.add(map1);
        lists.add(map2);
        return lists;
    }

    /**
     * map集合转换为object集合
     * @param lists
     * @return
     */
    private static List<User> zhuanhuan(List<Map<String, Object>> lists) {
        List<User> users = new ArrayList<>();
        for (Map<String, Object> list : lists) {
            User user  = new User(list);
            users.add(user);
        }
        return users;
    }
}

总结:mybatis中查询操作通常是返回一个实体对象集合。但在一些特殊情况下,返回一个map集合对象。在业务层需要将map集合对象转化为实体对象集合,上面的例子简单的举例说明了转换思想。

<think>嗯,用户现在问的是关于Map集合的面试题。之前他们问过Spring注解,现在向Java集合,可能是在准备Java相关的面试,需要复习常见的问题。首先,我需要回忆常见的Map相关的面试题,比如HashMap的工作原理、线程安全问题、ConcurrentHashMap的实现,还有红黑树和链表的结构转换等。 用户可能希望得到全面的问题列表和详细的解答,但需要结构清晰,分点说明。可能他们需要对比不同Map实现类的区别,比如HashMap、Hashtable、ConcurrentHashMap。还要注意源码层面的问题,比如hash计算、扩容机制。 另外,考虑到之前的回答用了Markdown,并且分模块,这次也需要保持类似的格式,让内容易读。可能需要包括基本概念、常见问题、源码解析、使用场景和注意事项等部分。 还要注意用户可能的盲点,比如JDK8之后HashMap引入红黑树的优化,ConcurrentHashMap的分段锁和CAS操作。此外,线程安全的问题和如何解决也是常见考点。 需要确保回答准确,比如HashMap的负载因子默认值,扩容倍数,以及为什么长度是2的幂次。同时,解答要尽量详细,但不过于冗长,适合面试准备时快速回顾。 可能还需要加入一些代码示例,比如如何正确使用HashMap,或者ConcurrentHashMap的线程安全示例。另外,强调实践中的最佳做法,比如初始化容量,选择合适的Map实现类。 最后,检查是否有遗漏的重要问题,比如哈希冲突解决、遍历方式、fail-fast机制等。确保覆盖所有常见考点,帮助用户全面准备。</think>以下是关于 Java `Map` 集合的常见面试题及详解,内容覆盖底层原理、高频考点和实际应用场景,帮助系统性准备面试: --- ### **一、基础概念** 1. **Map 的核心特点** - **键值对存储**:通过 `Key` 快速查找 `Value`,`Key` 不可重复,`Value` 可重复。 - **常用实现类**: - `HashMap`(无序,线程不安全) - `LinkedHashMap`(有序,按插入或访问顺序) - `TreeMap`(有序,按 `Key` 自然排序或自定义比较器) - `Hashtable`(线程安全,已逐渐被 `ConcurrentHashMap` 替代) - `ConcurrentHashMap`(高并发场景下的线程安全实现) 2. **HashMap 与 Hashtable 的区别** | **特性** | **HashMap** | **Hashtable** | |----------------|-------------------|-------------------| | **线程安全** | 不安全 | 安全(方法用 `synchronized` 修饰) | | **Null 支持** | 允许 `Key` 和 `Value` 为 `null` | `Key` 和 `Value` 均不可为 `null` | | **性能** | 更高(无锁竞争) | 较低(锁粒度大) | | **初始容量** | 16 | 11 | --- ### **二、高频考点(HashMap 底层原理)** #### **1. 数据结构与哈希冲突解决** - **JDK 1.7 及之前**:数组 + 链表(哈希冲突时,新元素插入链表头部)。 - **JDK 1.8 及之后**:数组 + 链表/红黑树(链表长度 ≥ 8 且数组长度 ≥ 64 时,链表为红黑树)。 ```java // JDK 1.8 的节点定义(链表或红黑树) static class Node<K,V> implements Map.Entry<K,V> { final int hash; final K key; V value; Node<K,V> next; // 链表结构 } ``` #### **2. 哈希函数设计** - **核心逻辑**:`Key` 的 `hashCode()` 经过扰动计算(减少哈希冲突)。 ```java // JDK 1.8 的扰动函数 static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } ``` - **数组长度为什么是 2 的幂次?** 方便通过 `(n - 1) & hash` 快速定位索引,等同于取模运算(`hash % n`),但位运算效率更高。 #### **3. 扩容机制(Resize)** - **触发条件**:当元素数量超过 `容量 × 负载因子`(默认负载因子 `0.75`)。 - **扩容操作**: 1. 创建新数组(大小为原数组的 2 倍)。 2. 重新计算每个元素的哈希位置(利用高位判断,避免全量重新哈希)。 - **链表拆分优化(JDK 1.8)**: 根据 `hash & oldCap` 是否为 0,将链表拆分为低位链表(原索引)和高位链表(原索引 + 原容量)。 --- ### **三、线程安全问题** #### **1. HashMap 为什么线程不安全?** - **场景 1:多线程扩容导致死循环(JDK 1.7)** 链表头插法在并发扩容时可能形成环形链表,导致 `get()` 死循环。 - **场景 2:数据覆盖(JDK 1.8)** 多线程同时执行 `put()` 时,可能覆盖已写入的键值对。 #### **2. ConcurrentHashMap 如何保证线程安全?** - **JDK 1.7**:分段锁(Segment),每个段独立加锁,降低锁粒度。 - **JDK 1.8**: - 取消分段锁,采用 `Node` 数组 + `CAS`(无锁化操作) + `synchronized`(仅锁住链表头或红黑树根节点)。 - **关键代码片段**: ```java final V putVal(K key, V value, boolean onlyIfAbsent) { // 使用 CAS 尝试无锁插入 if ((f = tabAt(tab, i = (n - 1) & hash)) == null) { if (casTabAt(tab, i, null, new Node<K,V>(hash, key, value))) break; } // 若存在哈希冲突,则对头节点加 synchronized 锁 else { synchronized (f) { // 插入或更新节点 } } } ``` --- ### **四、进阶问题** #### **1. LinkedHashMap 如何实现有序性?** - 继承 `HashMap`,通过双向链表维护插入顺序或访问顺序(LRU 缓存的基础)。 - **访问顺序模式**:重写 `removeEldestEntry()` 可实现固定大小的 LRU 缓存。 #### **2. TreeMap 的排序规则** - 基于红黑树实现,支持: - **自然排序**:`Key` 实现 `Comparable` 接口。 - **定制排序**:通过 `Comparator` 传入比较器。 #### **3. 如何设计一个线程安全的 Map?** - **方案 1**:使用 `Collections.synchronizedMap(new HashMap<>())`(锁住整个 Map)。 - **方案 2**:使用 `ConcurrentHashMap`(推荐,锁粒度更小)。 - **方案 3**:自定义锁分段(参考 JDK 1.7 的 `ConcurrentHashMap` 实现)。 --- ### **五、实战技巧** 1. **初始化容量优化** - 预估数据量,避免频繁扩容(如数据量 1000,负载因子 0.75,则初始容量设为 `(1000 / 0.75) + 1 ≈ 1334`)。 2. **Key 的选择** - 使用不可变对象(如 `String`、`Integer`),避免修改 `Key` 导致哈希值变化。 3. **遍历方式** - 使用 `entrySet()` 遍历(直接获取键值对,效率高于 `keySet()` + `get()`)。 --- ### **六、常见面试题示例** 1. **HashMap 的负载因子为什么默认是 0.75?** - 权衡时间与空间:负载因子过小(如 0.5)会导致频繁扩容,过大(如 1.0)会增加哈希冲突概率。 2. **ConcurrentHashMap 的 size() 方法如何实现?** - JDK 1.8 中基于 `baseCount` 和 `CounterCell[]` 的分段统计,减少并发竞争。 3. **如何让 HashMap 支持插入顺序遍历?** - 改用 `LinkedHashMap`,并在构造方法中设置 `accessOrder=false`(默认按插入顺序)。 --- 通过理解这些核心问题,可以系统性地掌握 `Map` 的设计思想和应用场景,应对面试中的深度追问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值