Java集合框架--Map接口与Collections类

Map接口及其多个实现类的对比

  • Map:双列数据,存储key-value对的数据

    • HashMap:作为Map的主要实现类;线程不安全,效率高;可以存储null的key和value

      • LinkedHashMap:保证在遍历map元素时,可以按照添加的顺序实现遍历。

        ​ 原因:在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。

        ​ 对于频繁的遍历操作,此类的执行效率高于HashMap

    • TreeMap:保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序

      ​ 底层使用红黑树

    • Hashtable:作为Map的古老实现类;线程安全,效率低;不可以存储null的key和value(java.lang.NullPointerException)

      • Properties:常用来处理配置文件;key和value都是String类
  • HashMap的底层:数组+链表(jdk7以及之前)

    ​ 数组+链表+红黑树(jdk8)

  • 重点:HashMap的底层实现原理

    HashMap和Hashtable的异同

    CurrentHashMap与Hashtable的异同(暂时无)

Map中存储的key-value的特点

在这里插入图片描述

  • Map中的key:无序的、不可重复的,使用Set存储所有的key---->key所在类要重写equals()和hashCode() (以HashMap为例)
  • Map中的value:无序的、可重复的,使用Collection存储所有的value
  • 一个key-value键值对构成了一个Entry对象
  • Map中的entry:无序的、不可重复的,使用Set存储所有的entry

HashMap在JDK7中的底层实现原理

  • HashMap map = new HashMap(); 在实例化以后,底层创建了长度是16的一维数组Entry[] table,

    …可能已经执行过多次put

    map.put(key1,value1);
    //首先,调用key1所在类的hashCode()计算key1哈希值,此哈希值经过某种算法计算以后,得到在Entry数组中的存放位置
    //若此位置上的数据为空,此时的key1-value1添加成功    --->情况1
    //如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在),比较key1和已经存在的一个或多个数据的哈希值:
    	//如果key1的哈希值与已经存在的数据的哈希值不同,则key1-value1的哈希值添加成功 --->情况2
    	//如果key1的哈希值与已经存在的数据(key2-value2)的哈希值相同,则继续比较:调用key1所在类的equals()方法,比较:
    		//如果equals()返回false:key1-value1添加成功 --->情况3
    		//如果equals()返回true:使用value1替换value2
    

    ​ 补充:关于情况2和3,此时key1-value1和原来的数据以链表的形式存储

    ​ 在不断的添加过程中会涉及到扩容问题,默认的扩容方式:扩容为原来容量的 2倍,并将原有的数据复制过来

HashMap在JDK8中的底层实现原理

  • jdk8相较于jdk7在底层方面实现的不同:

    1. new HashMap():底层没有创建一个长度为16的数组

    2. jdk8底层的数组是Node[]而非Entry[]

    3. 首次调用put方法时,底层创建长度为16的数组

    4. jdk7底层结构只有数组+链表,jdk8底层结构:数组+链表+红黑树

      当数组的某一个索引位置上的元素以链表形式存在的数据个数>8且当前数组长度>64,此时此索引位置上的所有数据改为使用红黑树存储

HashMap在JDK7、8中的源码分析

待我学成归来再写吧,暂时水平太低

HashMap源码中的重要常量

DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16

MAXIMUM_CAPACITY:HashMap的最大支持容量,2^30

DEFAULT_LOAD_FACTOR:HashMap的默认加载因子

TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树

UNTREEIFY_THRESHOLD:Bucket中红黑树存储的Node小于该默认值,转化为链表

MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量。(当桶中Node的

数量大到需要变红黑树时,若hash表容量小于MIN_TREEIFY_CAPACITY时,此时应执行

resize扩容操作这个MIN_TREEIFY_CAPACITY的值至少是TREEIFY_THRESHOLD的4

倍。)

table:存储元素的数组,总是2的n次幂

entrySet:存储具体元素的集

size:HashMap中存储的键值对的数量

modCount:HashMap扩容和结构改变的次数。

threshold:扩容的临界值,=容量*填充因子

loadFactor:填充因子

LinkedHashMap的底层实现

static class Entry<K,V> extends HashMap.Node<K,V> {
    Entry<K,V> before, after;
    Entry(int hash, K key, V value, Node<K,V> next) {
        super(hash, key, value, next);
    }
}

Map中的常用方法1

public class MapTest {
    @Test
    public void test(){
        Map map = new HashMap();
        //V put(K key, V value) 将指定的值与该映射中的指定键相关联

        //添加
        map.put("AA",123);
        map.put("BB",12);
        //修改
        map.put("AA",456);
        System.out.println(map);

        Map map1 = new HashMap();
        map1.put("CC",111);
        map1.put("DD",55);

        //void putAll(Map<? extends K,? extends V> m)  将指定Map的所有映射复制到此映射
        map.putAll(map1);
        System.out.println(map);

        //V remove(Object key) 如果存在,从该Map中删除一个键的映射。
        Object value = map.remove("CC");
        System.out.println(value);
        System.out.println(map);

        //void clear() 从该Map中删除所有的映射.
        map.clear();//与map= null操作不同
        System.out.println(map.size());//0
        System.out.println(map);

    }
    @Test
    public void test1(){
        Map map = new HashMap();
        map.put("AA",123);
        map.put("BB",12);
        map.put("AA",456);

        //V get(Object key) 返回到指定键所映射的值,或 null如果此映射包含该键的映射
        System.out.println(map.get("GG"));//null
        System.out.println(map.get("AA"));//456

        //boolean containsKey(Object key) 如果此映射包含指定键的映射,则返回true
        System.out.println(map.containsKey("AA"));

        //boolean containsValue(Object value) 如果此Map将一个或多个键映射到指定的值,则返回true
        System.out.println(map.containsValue(12));
        
    }
}

Map中的常用方法2

@Test
public void test2(){
    Map map = new HashMap();
    map.put("AA",123);
    map.put("BB",12);
    map.put("AA",456);
    map.put("CC",521);

    //遍历所有的key集
    Set set = map.keySet();
    Iterator iterator = set.iterator();
    while (iterator.hasNext()){
        System.out.println(iterator.next());
    }

    //遍历所有的value集
    Collection values = map.values();
    for (Object value : values) {
        System.out.println(value);
    }

    //遍历所有的entry集
    Set set1 = map.entrySet();
    Iterator iterator1 = set1.iterator();
    while (iterator1.hasNext()){
        System.out.println(iterator1.next());
    }
}

TreeMap两种添加方式的使用

public class TreeMapTest {
    //向TreeMap中添加key-value,要求key必须是由同一个类创建的对象
    //因为要按照key进行排序:自然排序、定制排序
    @Test
    public void test(){
        TreeMap map = new TreeMap();
        map.put(new User(12,"Tom"),11);
        map.put(new User(15,"Davis"),123);
        map.put(new User(20,"Lxy"),150);
        System.out.println(map);
        
        //定制排序
        Comparator com = new Comparator() {
            //按年龄从小到大排序
            @Override
            public int compare(Object o1, Object o2) {
                if (o1 instanceof User && o2 instanceof User){
                    User u1 = (User)o1;
                    User u2 = (User)o2;
                    return Integer.compare(u1.getAge(),u2.getAge());
                }else{
                    throw new RuntimeException("输入的数据类型不匹配");
                }
            }
        };
        TreeMap map1 = new TreeMap(com);
        map.put(new User(12,"Tom"),11);
        map.put(new User(15,"Davis"),123);
        map.put(new User(20,"Lxy"),150);
        System.out.println(map);
    }
}

Properties处理属性文件

  • Properties 类是 Hashtable 的子类,该对象用于处理属性文件

  • 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key

    和 value 都是字符串类型

  • 存取数据时,建议使用setProperty(String key,String value)方法和

    getProperty(String key)方法

public class PropertiesTest {
    @Test
    public void test() throws IOException {
        Properties pro = new Properties();
        FileInputStream fis = new FileInputStream("jdbc.properties");
        pro.load(fis);//加载流对应文件

        String name = pro.getProperty("name");
        String password = pro.getProperty("password");
        System.out.println("name = "+name+",password = "+password);
        fis.close();
    }
}
//在项目目录下添加jdbc.properties文件
//内容如下:
name=Tom
password=123

Collections工具类常用方法

  • Collections是操作Collection和Map的工具类
public class CollectionsTest {
    @Test
    public void test(){
        List list = new ArrayList();
        list.add(12);
        list.add(15);
        list.add(-1);
        list.add(-12);
        list.add(3);
        list.add(3);
        Collections.swap(list,0,3);
        Collections.max(list);
        int frequency = Collections.frequency(list,3);
        //List list1 = new ArrayList(); 报异常
        List list1 = Arrays.asList(new Object[list.size()]);
        Collections.copy(list1,list);//把list的内容复制到list1中
        System.out.println(list1);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值