0062 Map接口

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

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

/*
    Map接口实现类特点
    1.Map与Collection并列存在,用于保存具有映射关系的数据 Key-Value
    2.Map中的key和value可以是任何引用类型的数据,会封装到HashMap$Node对象中
    3.Map中的key不允许重复,可为null,只能有一个
    4.Map中的value可以重复,可为null,可以多个
    5.常用String类作为Map的key
    6.key和value之间存在单向一对一关系,即通过指定的key总能找到对应的value
    7.一对k-v是放在一个HashMap$Node中的,因为Node实现了Entry接口,也说一堆k-v就是一个Entry
 */
@SuppressWarnings({"all"})
public class Map_ {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("no1", "jack");
        map.put("no2", "tom");
        map.put("no1", "mary");//当有相同的key, 就等价于替换.
        map.put("no3", "tom");//value可以重复
        map.put(null, null);
        map.put(null, "abc");//等价替换
        map.put("no4", null);//value的null可以多个
        map.put("no5", null);
        map.put(new Object(), "smith");
        // 通过 get 方法,传入 key ,会返回对应的 value
        System.out.println(map.get("no2"));//tom
        System.out.println("map=" + map);

        //1.k-v最后是 HashMap$Node node = new Node(hash,key,value,null)
        //2.为方便遍历,还会创建EntrySet集合,该集合存放的元素类型Entry
        //  一个Entry对象就有k-v即: transient Set<Map.Entry<K,V>> entrySet;
        //3.在entrySet中,定义类型是Map.Entry,但实际上还是HashMap$Node
        //  因为 static class Node<K,V> implements Map.Entry<K,V>
        //4.当把HashMap$Node对象存放到entrySet就方便了我们遍历
        //  因为Map.Entry提供了方法 K getKey();V getValue()
        Set set = map.entrySet();
        System.out.println(set.getClass());//class java.util.HashMap$EntrySet
        for (Object obj : set) {
            // System.out.println(entry.getClass());//class java.util.HashMap$Node
            //从HashMap$Node取出k-v
            Map.Entry entry = (Map.Entry) obj;//向下转型
            System.out.println(entry.getKey() + "-" + entry.getValue());
        }

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

/*
    Map接口常用方法
    1.put                   //添加
    2.remove                //根据键删除
    3.get                   //获取值
    4.size                  //获取元素个数
    5.isEmpty               //判断是否为空
    6.clear                 //清空
    7.containsKey           //查找键是否存在
 */
@SuppressWarnings({"all"})
public class Map02 {
    public static void main(String[] args) {
        Map map = new HashMap();
        //put
        map.put("001","jack");
        map.put("002","tom");
        map.put("003","smith");
        System.out.println(map);//{001=jack, 002=tom, 003=smith}

        //remove
        map.remove("001");
        System.out.println(map);//{002=tom, 003=smith}

        //get
        System.out.println(map.get("002"));//tom

        //size
        System.out.println(map.size());//2

        //isEmpty
        System.out.println(map.isEmpty());//false

        //clear
        map.clear();
        System.out.println(map);//{}

        //containsKey
        System.out.println(map.containsKey("003"));//false
    }
}
import java.util.*;

/*
    containsKey:查找键是否存在
    keySet:获取所有键
    entrySet:获取所有关系
    values:获取所有值

    遍历方式
    1.取出所有的key,通过key取出对应的value
        增强for
        迭代器
    2.把所有values取出
        增强for
        迭代器
    3.通过EntrySet获取
        增强for
        迭代器

   HashMap小结
    1.Map接口常用实现类:HashMap,Hashtable,Properties
    2.HashMap是Map接口使用频率最高的实现类
    3.HashMap是以key-value对的方式来存储数据(HashMap$Node)
    4.与HashSet一样,不保证映射的顺序,因为底层以hash表的形式存储(数组+链表+红黑树)
    5.HashMap没有实现同步,因此线程不安全
 */
@SuppressWarnings({"all"})
public class Map03 {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("001","jack");
        map.put("002","tom");
        map.put("003","smith");

        //1.取出所有的key,通过key取出对应的value
        Set set = map.keySet();
        System.out.println("==========增强for=============");
        for (Object key :set) {
            System.out.println(key + "-" + map.get(key));
        }
        System.out.println("==========迭代器=============");
        Iterator iterator1 = set.iterator();
        while (iterator1.hasNext()) {
            Object key =  iterator1.next();
            System.out.println(key + "-" + map.get(key));
        }

        //2.把所有values取出
        Collection values = map.values();
        System.out.println("==========增强for=============");
        for (Object value :values) {
            System.out.println(value);
        }
        System.out.println("==========迭代器=============");
        Iterator iterator2 = values.iterator();
        while (iterator2.hasNext()) {
            Object value =  iterator2.next();
            System.out.println(value);
        }

        // 3.通过EntrySet获取
        Set entrySet = map.entrySet();
        System.out.println("==========增强for=============");
        for (Object entry :entrySet) {
            Map.Entry m = (Map.Entry) entry;//将entry转成Map.Entry,使用方法get()
            System.out.println(m.getKey() + "-" + m.getValue());
        }
        System.out.println("==========迭代器=============");
        Iterator iterator3 = entrySet.iterator();
        while (iterator3.hasNext()) {
            Object entry =  iterator3.next();
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey() + "-" + m.getValue());
        }

    }
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

/*
    练习
    使用HashMap添加3个员工对象,要求键:员工id,值:员工对象
    遍历显示工资>18000的员工
    员工类:id、姓名、工资
 */
@SuppressWarnings({"all"})
public class Map04 {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put(1,new Employee("tom",001,10000));
        map.put(2,new Employee("jack",002,19999));
        map.put(3,new Employee("jhon",003,20000));

        Set set = map.keySet();
        System.out.println("使用增强for");
        for (Object key : set) {
            //获取value
            Employee employee = (Employee) map.get(key);
            if (employee.getSalary() > 18000){
                System.out.println(employee);
            }
        }
        System.out.println("使用EntrySet");
        Set entrySet = map.entrySet();
        Iterator iterator = entrySet.iterator();
        while (iterator.hasNext()) {
            Map.Entry entry =  (Map.Entry)iterator.next();
            //通过entry取得k-v
            Employee employee = (Employee)entry.getValue();
            if (employee.getSalary() > 18000){
                System.out.println(employee);
            }

        }

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

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

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

    public int getId() {
        return id;
    }

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}
import java.util.HashMap;

/*
    HashMap底层
    扩容机制和HashSet一致
    1.HashMap底层维护了Node类型的数组table,默认为null
    2.当创建对象时,将加载因子初始化为0.75
    3.当添加key-value时,通过key的hash值得到在table的索引,判断该索引是否有元素
      如果没有直接添加,如果有,则判断该元素的key和准备加入的key是否相等
      如果相等,直接替换value,如果不相等,判断是树结构还是链表结构,做相应处理
      如果容量不够,则扩容
    4.第一次添加,扩容table容量为16,临界值为12(16*0.75)
    5.以后再扩容,则扩容table容量为原来的两倍(16-32-64..),临界值为原来的两倍(12-24-48..)
    6.在Java8中,如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认为8),且table大小>=MIN_TREEIFY_CAPACITY(默认64)
      就会进行树化(红黑树),否则仍然采用数组扩容机制
 */
@SuppressWarnings({"all"})
public class Map05 {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("01","java");
        map.put("02","c++");
        map.put("01","python");//替换value
        System.out.println(map);

    }
}
/*
        1.执行构造器 new HashMap()
            初始化加载因子 loadFactor = 0.75
            HashMap$Node[] table = null

        2.执行put 调用hash方法,计算key的hash值
          public V put(K key, V value) {//K="01",value="java"
            return putVal(hash(key), key, value, false, true);
            }

        3.执行putVal
            final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i;;//辅助变量
        //如果底层的 table 数组为 null, 或者 length =0 , 就扩容到 16
            if ((tab = table) == null || (n = tab.length) == 0)
                n = (tab = resize()).length;
        //取出hash值对应的table的索引位置的Node,如果为null,就直接把加入的k-v创建成Node加入到该位置
            if ((p = tab[i = (n - 1) & hash]) == null)
                tab[i] = newNode(hash, key, value, null);
            else {
                Node<K,V> e; K k;//辅助变量
        // 如果 table 的索引位置的 key 的 hash 值和新的 key 的 hash 值相同,
        // 并 满足(table 现有的结点的 key 和准备添加的 key 是同一个对象 || equals 返回真)
        // 就认为不能加入新的 k-v
                if (p.hash == hash &&
                    ((k = p.key) == key || (key != null && key.equals(k))))
                    e = p;
                else if (p instanceof TreeNode))
            //如果当前的 table 的已有的 Node 是红黑树,就按照红黑树的方式处理
                    e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
                else {
            //如果找到的结点,后面是链表,就循环比较
                    for (int binCount = 0; ; ++binCount) {//死循环
                        if ((e = p.next) == null) {{//如果整个链表,没有和他相同,就加到该链表的最后
                            p.next = newNode(hash, key, value, null);
            //加入后,判断当前链表的个数,是否已经到8,到8个就调用treeifyBin方法进行红黑树的转换
                            if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                treeifyBin(tab, hash);
                            break;
                        }
            //如果在循环比较过程中,发现有相同,就 break,就只是替换 value
                        if (e.hash == hash &&
                            ((k = e.key) == key || (key != null && key.equals(k))))
                            break;
                        p = e;
                    }
                }
                if (e != null) { // existing mapping for key
                    V oldValue = e.value;
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value;//替换,key 对应 value
                    afterNodeAccess(e);
                    return oldValue;
                }
            }
            ++modCount;//每增加一个 Node ,就 size++
            if (++size > threshold)//如 size > 临界值,就扩容
                resize();
            afterNodeInsertion(evict);
            return null;
        }
    //如果 table 为 null ,或者大小还没有到 64,暂时不树化,而是进行扩容
        final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
            resize();
 */
import java.util.Hashtable;

/*
    HashTable
    1.存放的元素是键值对,即K-V
    2.HashTable的键和值都不能为null
    3.HashTable使用方法基本和HashMap一致
    4.HashTable是线程安全的,HashMap是线程不安全的

    底层
    1.有数组Hashtable$Entry[] 初始化为11
    2.临界值为11*0.75=8
    扩容
    int newCapacity = (oldCapacity << 1) + 1; 即两倍+1
    即 第二次扩容 11*2+1=23  第三次23*2+1=47 ...
       临界值 23*0.75=17     47*0.75=35 ....

 */
@SuppressWarnings({"all"})
public class Map06 {
    public static void main(String[] args) {
        Hashtable table = new Hashtable();
        table.put("john",100);
        //table.put(null,100);//空指针异常NullPointerException
        //table.put("smith",null);//空指针异常NullPointerException
        table.put("jack",200);
        table.put("john",300);//替换value
        System.out.println(table);
    }
}
import java.util.Properties;
/*
    Properties
    1.Properties类继承了Hashtable类且实现了Map接口,也是使用键值对的形式保存数据
    2.使用特点和Hashtable类似
    3.Properties还可用于从xxx.Properties文件中,加载数据到Properties类对象,并进行读取和修改
      xxx.Properties文件通常为配置文件
 */
public class Map07 {
    public static void main(String[] args) {
        // Properties 继承 Hashtable,可以通过 k-v存放数据,key 和 value 不能为 null
        // 增
        Properties properties = new Properties();
        //properties.put(null, "abc");//抛出 空指针异常
        //properties.put("abc", null); //抛出 空指针异常
        properties.put("john", 100);//k-v
        properties.put("lucy", 100);
        properties.put("jack", 100);
        properties.put("john", 999);//相同key,value被替换
        System.out.println(properties);
        //删
        properties.remove("lucy");
        System.out.println(properties);
        //改
        properties.put("john", "smith");
        System.out.println(properties);
        //查
        System.out.println(properties.get("jack"));
    }
}
import java.util.Comparator;
import java.util.TreeSet;
/*
    TreeSet
    1.使用无参构造器,创建TreeSet时,仍然时无序的
    2.使用有参构造器,传入一个比较器(匿名内部类),并指定排序规则
 */
@SuppressWarnings({"all"})
public class Map08 {
    public static void main(String[] args) {
        TreeSet treeSet = new TreeSet();
        //使用无参构造器,创建TreeSet时,仍然时无序的
        treeSet.add("tom");
        treeSet.add("jack");
        treeSet.add("smith");
        treeSet.add("mary");
        treeSet.add("jhon");
        System.out.println(treeSet);
       // 希望添加的元素按照字符串大小排序
       TreeSet treeSet2 = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return (((String) o1).length() - ((String) o2).length());//按照长度大小排序,相同长度就加入不了
                //return ((String) o1).compareTo((String) o2);//调用String的compareTo方法进行字符串大小比较
            }
        });
        treeSet2.add("tom");
        treeSet2.add("jack");
        treeSet2.add("smith");
        treeSet2.add("mary");//长度相同,加入不了
        treeSet2.add("jhon");//长度相同,加入不了
        System.out.println(treeSet2);
    }
}
/*
    1. 构造器把传入的比较器对象,赋给了 TreeSet 的底层的 TreeMap 的属性 this.comparator
            public TreeMap(Comparator<? super K> comparator) {
             this.comparator = comparator;
             }
     2. 在 调用 treeSet.add("tom"), 在底层会执行到if (cpr != null) {//cpr 就是我们的匿名内部类(对象)
            do {
                 parent = t;
                //动态绑定到我们的匿名内部类(对象)compare
                cmp = cpr.compare(key, t.key);
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else //如果相等,即返回 0,这个 Key 就没有加入
                    return t.setValue(value);
            } while (t != null)
 */
import java.util.Comparator;
import java.util.TreeMap;

/*
    TreeMap
    1.使用无参构造器,创建TreeSet时,仍然时无序的
    2.使用有参构造器,传入一个比较器(匿名内部类),并指定排序规则
 */
@SuppressWarnings({"all"})
public class Map09 {
    public static void main(String[] args) {
        TreeMap treeMap = new TreeMap();
        treeMap.put("jack","杰克");
        treeMap.put("mary","玛丽");
        treeMap.put("tom","汤姆");
        treeMap.put("smith","史密斯");
        System.out.println(treeMap);

        TreeMap treeMap1 = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
               // return ((String) o1).compareTo((String) o2);//按照Key(String)的大小比较
                return (((String) o1).length() - ((String) o2).length());//按照长度比较,相同长度就替换
            }
        });
        treeMap1.put("jack","杰克");
        treeMap1.put("mary","玛丽");//替换杰克
        treeMap1.put("tom","汤姆");
        treeMap1.put("smith","史密斯");
        System.out.println(treeMap1);
    }
}

/*
    1. 构造器. 把传入的实现了 Comparator 接口的匿名内部类(对象),传给给 TreeMap 的 comparator
            public TreeMap(Comparator<? super K> comparator) {
                this.comparator = comparator;
            }
    2. 调用 put 方法
    2.1 第一次添加, 把 k-v 封装到 Entry 对象,放入 root
            Entry<K,V> t = root;
            if (t == null) {
                compare(key, key); // type (and possibly null) check
                root = new Entry<>(key, value, null);
                size = 1;
                modCount++;
                return null;
             }

     2.2 以后添加
     Comparator<? super K> cpr = comparator;
      if (cpr != null) {
            do { //遍历所有的 key , 给当前 key 找到适当位置
                parent = t;
                cmp = cpr.compare(key, t.key);//动态绑定到我们的匿名内部类的 compare
                if (cmp < 0)
                    t = t.left;
                else if (cmp > 0)
                    t = t.right;
                else //如果遍历过程中,发现准备添加 Key 和当前已有的 Key 相等,就不添加
                    return t.setValue(value);
             } while (t != null);
 */

 

 

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

nzmzmc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值