24-08-08 JavaSE Map集合

24-08-08 javaSE Map集合

Map接口的特点

image-20240809000434507

  1. Map与Collection并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)

  2. Map 中的 key 和 value 可以是任何引用类型的数据,会封装到HashMap$Node 对象中

    3.  Map 中的 key 不允许重复,原因和HashSet 一样,前面分析过源码.
    
  3. Map 中的 value 可以重复

  4. Map 的key 可以为 null, value 也可以为null ,注意 key 为null,
    只能有一个,value 为null ,可以多个

  5. 常用String类作为Map的 key

  6. key 和 value 之间存在单向一对一关系,即通过指定的 key 总能找到对应的 value

@SuppressWarnings({"all"})
public class Map_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("no1", "韩顺平");//k-v
        map.put("no2", "张无忌");//k-v
        map.put("no1", "张三丰");//当有相同的k , 就等价于替换.
        map.put("no3", "张三丰");//k-v
        map.put(null, null); //k-v
        map.put(null, "abc"); //等价替换
        map.put("no4", null); //k-v
        map.put("no5", null); //k-v
        map.put(1, "赵敏");//k-v
        map.put(new Object(), "金毛狮王");//k-v
        // 通过get 方法,传入 key ,会返回对应的value
        System.out.println(map.get("no2"));//张无忌
        System.out.println("map=" + map);
    }
}

张无忌
map={no2=张无忌, null=abc, no1=张三丰, 1=赵敏, no4=null, java.lang.Object@1eb44e46=金毛狮王, no3=张三丰, no5=null}

Map接口源码讲解

@SuppressWarnings({"all"})
public class MapSource_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("no1", "韩顺平");//k-v
        map.put("no2", "张无忌");//k-v
        map.put(new Car(), new Person());//k-v
        Set set = map.entrySet();
        System.out.println(set.getClass());// HashMap$EntrySet
        for (Object obj : set) {
        Map.Entry entry = (Map.Entry) obj;
        System.out.println(entry.getKey() + "-" + entry.getValue() );
        }
        Set set1 = map.keySet();
        System.out.println(set1.getClass());
        Collection values = map.values();
        System.out.println(values.getClass());
    }
}

class Car {

}

class Person{

}
  1. k-v 最后是 HashMap$Node node = newNode(hash, key, value, null),Node是内部类

image-20240809002501915

image-20240809002526470

  1. k-v 为了方便程序员的遍历,还会 创建 EntrySet 集合 ,该集合存放的元素的类型 Entry, 而一个Entry对象就有k,v 。相当于EntrySet<Entry<K,V>>

  2. image-20240809003343596

    image-20240809002806869

    Set set = map.entrySet(); System.out.println(set.getClass());// HashMap$EntrySet
    
  3. entrySet 中, 定义的类型是 Map.Entry ,但是实际上存放的还是 HashMap$Node,因为node类型实现了Entry;

image-20240809003904717

  1. 当把 HashMap$Node 对象 存放到 entrySet 就方便我们的遍历, 因为 Map.Entry类 提供了重要方法K getKey(); V getValue();
for (Object obj : set) {       System.out.println(obj.getClass()); 				//HashMap$Node
    //为了从 HashMap$Node 取出k-v
    //1. 先做一个向下转型
    Map.Entry entry = (Map.Entry) obj;
    System.out.println(entry.getKey() + "-" + entry.getValue() );
}

总结:首先HashMap里面的Note类型节点的引用会先转为Entry类型(因为node实现了entry)然后这个entry类型结点会放到EntrySet里面,EntrySet里面的key和Value值分别以set和collection形式存储,当然存储的也是引用。

我们可以更加直观的看到node->Entry的指向关系。

image-20240809005405292

我们可以更直观的看到EntrySet里面的key和Value值分别以set和collection形式存储(为了能够单独拿出来)

Set set1 = map.keySet();
System.out.println(set1.getClass());
Collection values = map.values();
System.out.println(values.getClass());

image-20240809005749840

KeySet继承AbstractSet,Values是继承AbstractSet的

image-20240809005957581

image-20240809010013855

我们对下面这张图片有了更清晰的认识image-20240809002806869

Map的常用方法

Map map = new HashMap();
        map.put("邓超", new Book("", 100));//OK
        map.put("邓超", "孙俪");//替换-> 一会分析源码
        map.put("王宝强", "马蓉");//OK
        map.put("宋喆", "马蓉");//OK
        map.put("刘令博", null);//OK
        map.put(null, "刘亦菲");//OK
        map.put("鹿晗", "关晓彤");//OK
        map.put("hsp", "hsp的老婆");
        System.out.println("map=" + map);
//        remove:根据键删除映射关系
        map.remove(null);
        System.out.println("map=" + map);
//        get:根据键获取值
        Object val = map.get("鹿晗");
        System.out.println("val=" + val);
//        size:获取元素个数
        System.out.println("k-v=" + map.size());
//        isEmpty:判断个数是否为0
        System.out.println(map.isEmpty());//F
//        clear:清除k-v
        //map.clear();
        System.out.println("map=" + map);
//        containsKey:查找键是否存在
        System.out.println("结果=" + map.containsKey("hsp"));//T


    }
}

class Book {
    private String name;
    private int num;

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

输出如下:

image-20240809010341843

Map接口三种途径的遍历方法

@SuppressWarnings({"all"})
public class MapFor {
    public static void main(String[] args) {

        Map map = new HashMap();
        map.put("邓超", "孙俪");
        map.put("王宝强", "马蓉");
        map.put("宋喆", "马蓉");
        map.put("刘令博", null);
        map.put(null, "刘亦菲");
        map.put("鹿晗", "关晓彤");

        //第一组: 先取出 所有的Key , 通过Key 取出对应的Value
        Set keyset = map.keySet();
        //(1) 增强for
        System.out.println("-----第一种方式-------");
        for (Object key : keyset) {
            System.out.println(key + "-" + map.get(key));
        }
        //(2) 迭代器
        System.out.println("----第二种方式--------");
        Iterator iterator = keyset.iterator();
        while (iterator.hasNext()) {
            Object key =  iterator.next();
            System.out.println(key + "-" + map.get(key));
        }


        //第二组: 把所有的values取出
        Collection values = map.values();
        //这里可以使用所有的Collections使用的遍历方法
        //(1) 增强for
        System.out.println("---取出所有的value 增强for----");
        for (Object value : values) {
            System.out.println(value);
        }
        //(2) 迭代器
        System.out.println("---取出所有的value 迭代器----");
        Iterator iterator2 = values.iterator();
        while (iterator2.hasNext()) {
            Object value =  iterator2.next();
            System.out.println(value);

        }

        //第三组: 通过EntrySet 来获取 k-v
        Set entrySet = map.entrySet();// EntrySet<Map.Entry<K,V>>
        //(1) 增强for
        System.out.println("----使用EntrySet 的 for增强(第3种)----");
        for (Object entry : entrySet) {
            //向下转型 将entry 转成 Map.Entry
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey() + "-" + m.getValue());
        }
        //(2) 迭代器
        System.out.println("----使用EntrySet 的 迭代器(第4种)----");
        Iterator iterator3 = entrySet.iterator();
        while (iterator3.hasNext()) {
            Object entry =  iterator3.next();
            //System.out.println(next.getClass());//HashMap$Node -实现-> Map.Entry (getKey,getValue)
            //向下转型 Map.Entry
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey() + "-" + m.getValue());
        }


    }
}

注:所有继承Collection接口的类都可以使用iterator迭代器。

输出结果如下:

-----第一种方式-------
邓超-孙俪
宋喆-马蓉
刘令博-null
null-刘亦菲
王宝强-马蓉
鹿晗-关晓彤
----第二种方式--------
邓超-孙俪
宋喆-马蓉
刘令博-null
null-刘亦菲
王宝强-马蓉
鹿晗-关晓彤
—取出所有的value 增强for----
孙俪
马蓉
null
刘亦菲
马蓉
关晓彤
—取出所有的value 迭代器----
孙俪
马蓉
null
刘亦菲
马蓉
关晓彤
----使用EntrySet 的 for增强(第3种)----
邓超-孙俪
宋喆-马蓉
刘令博-null
null-刘亦菲
王宝强-马蓉
鹿晗-关晓彤
----使用EntrySet 的 迭代器(第4种)----
邓超-孙俪
宋喆-马蓉
刘令博-null
null-刘亦菲
王宝强-马蓉
鹿晗-关晓彤

进程已结束,退出代码为 0

Map接口练习题

image-20240809015703848

@SuppressWarnings({"all"})
public class MapExercise {
    public static void main(String[] args) {
        Employee xiaoming = new Employee("小明", 50000, "123456");
        Employee xiaohong = new Employee("小红", 10000, "123457");
        Employee xiaofang = new Employee("小芳", 3000, "123458");
        Map hashMap = new HashMap();
        hashMap.put(xiaoming.getId(), xiaoming);
        hashMap.put(xiaohong.getId(), xiaohong);
        hashMap.put(xiaofang.getId(), xiaofang);
        Set set = hashMap.keySet();
        for (Object object : set) {
            Employee employee = (Employee) hashMap.get(object);
            if (employee.getSalary() > 18000)
                System.out.println(object + "-" + hashMap.get(object));
        }

//        Iterator iterator = set.iterator();
//        while (iterator.hasNext()) {
//            Object next = iterator.next();
//            System.out.println(next + "-" + hashMap.get(next));
//        }

        Set set1 = hashMap.entrySet();
//        for (Object object : set1) {
//            Map.Entry object1 = (Map.Entry) object;
//            System.out.println(object1.getKey() + "-" + object1.getValue());
//        }

        Iterator iterator1 = set1.iterator();
        while (iterator1.hasNext()) {
            Object next = iterator1.next();
            Map.Entry next1 = (Map.Entry) next;
            Employee value = (Employee) next1.getValue();
            if (value.getSalary() > 18000)
                System.out.println(next1.getKey() + "-" + next1.getValue());
        }


    }
}

class Employee {
    private String name;
    private double salary;
    private String id;

    public Employee(String name, double salary, String id) {
        this.name = name;
        this.salary = salary;
        this.id = id;
    }

    public String getName() {
        return name;
    }

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


    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "name='" + name + '\'' +
                ", salary=" + salary +
                ", id='" + id + '\'' +
                '}';
    }
}

HashMap小结

  1. Map接口的常用实现类:HashMap、Hashtable和Properties。

  2. HashMap是Map接口使用频率最高的实现类。

  3. HashMap 是以key-val对的方式来存储数据(HashMap$Node类型)

  4. key 不能重复,但是值可以重复,允许使用null键和null值。如果添加相同的key,则会覆盖原来的key-val,等同于修改.(key不会替换,val会替换)

    替换源码部分:

    image-20240809021331607

  5. 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.(jdk8的hashMap底层 数组+链表+红黑树)

  6. HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized

hMap小结

  1. Map接口的常用实现类:HashMap、Hashtable和Properties。

  2. HashMap是Map接口使用频率最高的实现类。

  3. HashMap 是以key-val对的方式来存储数据(HashMap$Node类型)

  4. key 不能重复,但是值可以重复,允许使用null键和null值。如果添加相同的key,则会覆盖原来的key-val,等同于修改.(key不会替换,val会替换)

    替换源码部分:

    [外链图片转存中…(img-bRXakQ9z-1723519058095)]

  5. 与HashSet一样,不保证映射的顺序,因为底层是以hash表的方式来存储的.(jdk8的hashMap底层 数组+链表+红黑树)

  6. HashMap没有实现同步,因此是线程不安全的,方法没有做同步互斥的操作,没有synchronized

持续更新。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值