Map接口

Map接口和常用方法

Map接口实现类的特点

  • 1,Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
  • 2,Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中,也可以说一对k-v就是一个Entry(因为Node实现了Entry接口)
    -,3,Map中的key不允许重复,当有相同的k,新的v就会替换之前的v
  • 4,Map中的value可以重复
  • 5,Map的key可以为null,value也可以为null。注意key为null,只能有一个,value为null,可以多个
  • 6,常用String类作为Map的key
  • 7,key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value
public class Map_ {
    @SuppressWarnings({"null"})
    public static void main(String[] args) {
        //使用实现类HashMap来解读Map实现类的特点
        HashMap map = new HashMap();
        map.put("no1","张三");//k-v
        map.put("no2","李四");
        map.put("no3","王五");
        //Map中的key不允许重复,当有相同的k,新的v就会替换之前的v
        map.put("no1","赵六");
        //Map中的value可以重复
        map.put("no4","李四");
        //Map的key可以为null,value也可以为null
        map.put(null,null);
        //注意key为null,只能有一个,value为null,可以多个
        map.put(1,null);
        map.put(null,2);
        //常用String类作为Map的key
        map.put(new Object(), "金毛狮王");//k-v
        //通过 get 方法,传入 key ,会返回对应的 value
        System.out.println(map.get("no1"));
        System.out.println("map="+map);

    }
}

结果
在这里插入图片描述

  • 8,Map存放数据key-value示意图,一对k-v是存放在HashMap$Node中,也可以说一对k-v就是一个Entry(因为Node实现了Entry接口)
    在这里插入图片描述

Map接口常用方法

  • 1,根据键删除映射关系 map.remove()
  • 2,获取,根据键value map.get() 输入k获取对应的v
  • 3,获取元素个数 map.size()
  • 4,判断个数是否为0 map.isEmpty()
  • 5,清除k-v map.clear();
  • 6,查找键k是否存在 map.containsKey()
public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("邓超",new Book("",100));
        map.put("邓超","孙俪");//替换
        map.put("王宝强", "马蓉");//OK
        map.put("宋喆", "马蓉");//OK
        map.put("刘令博", null);//OK
        map.put(null, "刘亦菲");//OK
        map.put("鹿晗", "关晓彤");//OK

        System.out.println("map="+map);

        //1,根据键删除映射关系  map.remove()
        map.remove(null);//删除k为null的对象
        System.out.println("map="+map);
        //2,获取,根据键value  map.get() 输入k获取对应的v
        System.out.println(map.get("邓超"));
        //3,获取元素个数  map.size()
        System.out.println(map.size());
        //4,判断个数是否为0  map.isEmpty()
        System.out.println(map.isEmpty());
        //5,清除k-v  map.clear();
        map.clear();
        System.out.println("清除后的map="+map);
        //6,查找键k是否存在  map.containsKey()
        System.out.println(map.containsKey("邓超"));//F

    }
}
class Book{
    private String name;
    private int num;

    public Book(String name, int num) {
        this.name = name;
        this.num = num;
    }
}

结果
在这里插入图片描述

Map接口遍历方法

首先:containKey 查找键是否存在
-方式1:先取出所有的键,然后根据键取出对应的值

  • 方式2,通过调用values方法来把所有的value取出
  • 方式3,通过EntrySet来获取k-v
public class MapMethod {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("邓超","孙俪");//OK
        map.put("王宝强", "马蓉");//OK
        map.put("宋喆", "马蓉");//OK
        map.put("刘令博", null);//OK
        map.put(null, "刘亦菲");//OK
        map.put("鹿晗", "关晓彤");//OK
        
        //containKey:查找键是否存在
        System.out.println(map.containsKey("邓超"));//T

        //方式1,先取出所有的键,然后根据键取出对应的值
        Set keyset = map.keySet();
        System.out.println("=======迭代器=======");
        Iterator iterator = keyset.iterator();
        while (iterator.hasNext()) {
            Object key =  iterator.next();
            System.out.println(key+"-"+map.get(key));
        }
        System.out.println("=========增强for========");
        for(Object o:keyset){
            System.out.println(o+"-"+map.get(o));
        }

        //方式2,通过调用values方法来把所有的value取出
        Collection values = map.values();
        System.out.println("=======取出所有value的迭代器=======");
        Iterator iterator1 = values.iterator();
        while (iterator1.hasNext()) {
            Object value = iterator1.next();
            System.out.println(value);
        }
        System.out.println("===========取出所有value的增强for===========");
        for (Object v:values){
            System.out.println(v);
        }
        //方式3,通过EntrySet来获取k-v
        Set entrySet = map.entrySet();
        System.out.println("======使用EntrySet迭代器=========");
        Iterator iterator2 = entrySet.iterator();
        while (iterator2.hasNext()) {
            Object entry = iterator2.next();
//            System.out.println(entry.getClass());//HashMap$Node -实现-> Map.Entry (getKey,getValue)
            //向下转型-Map.Entry
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey()+"-"+m.getValue());
        }

    }
}

结果
在这里插入图片描述

Map接口的常用实现类:HashMap、Hashable、Properties

Map接口实现类-HashMap

  • HashMap是Map接口使用频率最高的实现类
  • HashMap是以key-val对 的方式来存储数据(HashMap$Node类型)
  • key不能重复,但是value值可以重复,允许使用null键和null值
  • 如果添加相同的key,则会覆盖原来的key-val,等同于修改(key不会替换,val会替换)
  • 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的
  • HashMap没有实现同步,因此线程是不安全的,方法没有做同步互斥,没有synchronized
    在这里插入图片描述

HashMap的扩容机制

  • 1,HashMap底层维护了Node类型的数组table,默认为null
  • 2,当创建对象时,将加载因子(loadfactor)初始化为0.75
    执行构造器 new HashMap()
    初始化加载因子 loadfactor = 0.75
    HashMap$Node[] table = null
  • 3,当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key是否相等,如果相等就直接替换val;如果不相等需要判断是树结构还是链表结果,做出相应处理。如果添加时发现容量不够,则需要扩容
  • 4,第一次添加,则需要扩容table容量为16,临界值(threshold)为12(16*0.75)
  • 5,以后再扩容,则需要扩容table容量为原来的两倍(32),临界值为原来的两倍,即24,依次类推
  • 6,在Java8中,如果一条链表的元素个数超过TREEIFY_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

Map接口实现类-Hashtable

Hashtable的基本介绍

  • 存放的元素思键值对:即K-V
  • Hashtable的键和值都不能为null,否则会抛出NullPointerException
  • key不能重复,但是value值可以重复
  • 如果添加相同的key,则会覆盖原来的key-val,等同于修改(key不会替换,val会替换)
  • Hashtable使用的方法基本和HashMap一样
  • Hashtable是线程安全的(synchronized),HashMap是线程不安全的

Hashtable和HashMap对比

在这里插入图片描述

Map接口实现类-Properties

基本介绍

  • Properties类继承自Hashtable类并实现了Map接口,也是使用一种键值对的形式来保存数据
  • 它的使用特点和Hashtable类似
  • Properties还可以从xxx.properties文件中,加载数据到properties类对象,并进行读取和修改
public class Properties_ {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        Properties properties = new Properties();
//        properties.put(null,null);//抛出 空指针异常
        properties.put("john", 100);//k-v
        properties.put("lucy", 100);
        properties.put("lic", 100);
        properties.put("lic", 88);//如果有相同的 key , value 被替换

        System.out.println(properties);

        //通过 k 获取对应值
        System.out.println(properties.get("lic"));

        //删除
        System.out.println(properties.remove("lic"));
        //修改
        properties.put("john","乔治");
        System.out.println("john的v修改后"+properties);
    }
}

结果
在这里插入图片描述

总结-开发中如何选择结合实现类(记住)

开发中如何选择结合实现类,主要取决于 业务操作特点,然后根据集合实现类特性进行选择

  • 先判断存储的类型
    一组对象[单列]:Collection接口
    允许重复:List
    增删多:LinkedList【底层维护了一个双向链表】
    改查多:ArrayList【底层维护了 Object类型的可变数组】
    不允许重复:Set
    无序:HashSet【底层是HashMap,维护了一个哈希表】
    排序:TreeSet
    插入和取出顺序一致:LinkedHashSet,维护数组+双向链表
    一组键值对[双列]:Map
    键无序:HashMap【底层是:哈希表 jdk7:数组+链表 jdk8:数组+链表+红黑树】
    键排序:TreeMap
    键插入和取出一致:LinkedHashMap
    读取文件:Prpperities

TreeSet实现排序

使用TreeSet提供的一个构造器,传入一个比较器(匿名内部类new Comparator()) 来制定顺序

public class TreeSet_ {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //调用无参构造器,元素仍然是无序的
        TreeSet treeSet = new TreeSet();
        treeSet.add("jack");
        treeSet.add("tom");
        treeSet.add("zl");
        treeSet.add("aa");
//        System.out.println("未定序的treeSet="+treeSet);//无序

        //使用TreeSet提供的一个构造器,传入一个比较器(匿名内部类) 来制定顺序
        TreeSet treeSet1 = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                // 调用String 的compareTo方法进行字符串大小比较
//                return ((String)o1).compareTo((String)o2);
                //调用String 的 length方法,进行长度大小的比较
                return ((String)o1).length()-((String)o2).length();
            }
        });
        treeSet1.add("jack");
        treeSet1.add("tom");
        treeSet1.add("zl");
        treeSet1.add("a");

        System.out.println(treeSet1);


    }
}

结果
在这里插入图片描述

TreeMap实现排序

使用TreeMap提供的一个构造器,传入一个比较器(匿名内部类new Comparator()) 来制定顺序

public class TreeMap_ {
    @SuppressWarnings({"all"})
    public static void main(String[] args) {
        //调用无参构造器,元素仍然是无序的
        TreeMap treeMap = new TreeMap();
        treeMap.put("jack", "杰克");
        treeMap.put("tom", "汤姆");
        treeMap.put("kristina", "克瑞斯提诺");
        treeMap.put("smith", "斯密斯");
        System.out.println(treeMap);

        TreeMap treeMap1 = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //下面 调用 String 的 compareTo 方法进行字符串大小比较
//                return ((String)o2).compareTo(((String)o1));
                //调用String 的 length方法,进行长度大小的比较
                return ((String)o2).length()-((String)o1).length();
            }
        });
        treeMap1.put("jack", "杰克");
        treeMap1.put("tom", "汤姆");
        treeMap1.put("kristina", "克瑞斯提诺");
        treeMap1.put("smith", "斯密斯");
        System.out.println(treeMap1);


    }
}

结果
在这里插入图片描述

### select map 接口使用方法及功能 在 MyBatis 中,`select` 标签结合 `Map` 接口是一种常见的参数传递方式。通过这种方式,可以实现多参数查询,尤其适用于动态 SQL 场景。 #### 1. 使用 Map 作为参数 MyBatis 允许将 `Map` 作为参数传递给 SQL 映射语句。`Map` 的键用于标识参数名称,值为对应的参数值。以下是一个典型的例子: ```xml <select id="selectStu" resultType="com.wst.pojo.Stu" parameterType="map"> select * from stu where name like concat('%',#{u_name},'%') and age = #{u_age} </select> ``` 上述代码中,`parameterType="map"` 表示传递的是一个 `Map` 对象[^3]。在 Java 代码中,可以通过如下方式调用: ```java Map<String, Object> params = new HashMap<>(); params.put("u_name", "张"); params.put("u_age", 12); List<Stu> students = sqlSession.selectList("selectStu", params); ``` #### 2. 返回结果为 Map 除了作为参数外,`select` 标签也可以返回 `Map` 类型的结果。例如: ```xml <select id="getEmpReturnMap" resultType="map"> select * from employee where id = #{id} </select> ``` 这段代码会将查询结果以 `Map` 的形式返回,其中每一行数据对应一个 `Map`,键为列名,值为列值[^2]。 #### 3. 动态 SQL Map 结合 当需要根据多个条件动态生成 SQL 时,`Map` 是一种灵活的选择。例如: ```xml <select id="dynamicQuery" resultType="com.example.User" parameterType="map"> SELECT * FROM users WHERE 1=1 <if test="name != null"> AND name LIKE CONCAT('%', #{name}, '%') </if> <if test="age != null"> AND age = #{age} </if> </select> ``` Java 调用代码如下: ```java Map<String, Object> params = new HashMap<>(); params.put("name", "John"); params.put("age", 30); List<User> users = sqlSession.selectList("dynamicQuery", params); ``` #### 4. 与 JSP 的结合 在 Web 开发中,`Map` 可以用于填充下拉框(`<select>`)的内容。例如,在 Controller 中设置 `Map` 并传递到 JSP 页面: ```java request.setAttribute("maps", Constant.maps); ``` 然后在 JSP 页面中使用 JSTL 遍历 `Map` 并生成选项: ```jsp <select name="XXXX"> <option value="">=请选择=</option> <c:forEach items="${maps}" var="map"> <option value="${map.key}" ${object.value eq map.key ? 'selected' : ''}> ${map.value} </option> </c:forEach> </select> ``` 这段代码展示了如何将后端传递的 `Map` 数据渲染为前端的 `<select>` 元素[^1]。 #### 5. 限制替代方案 尽管 `Map` 提供了灵活性,但它也有一些缺点。由于 `Map` 的键是字符串类型,无法在编译时检查错误,且业务逻辑不够清晰[^4]。因此,对于复杂的 SQL 查询,推荐使用 Java Bean 作为参数类型。例如: ```xml <select id="selectUser" resultType="com.example.User" parameterType="com.example.UserParam"> SELECT * FROM users WHERE name LIKE CONCAT('%', #{name}, '%') AND age = #{age} </select> ``` 对应的 Java Bean 定义如下: ```java public class UserParam { private String name; private Integer age; // Getters and Setters } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值