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);


    }
}

结果
在这里插入图片描述

  • 23
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值