0
点赞
收藏
分享

微信扫一扫

集合框架(4)——Map、Set

烟中雯城 2022-02-07 阅读 132

一、Map接口

通过Key和Value存储数据的,Key和Value形成了一个映射关系

Map 用于保存具有映射关系的数据,因此 Map 集合里保存着两组值,一组值用于保存 Map 里的 Key ,另外一组用于保存 Map 里的 Value

Map 中的 key 和  value 都可以是任何引用类型的数据

Map 中的 Key 不允许重复

Key Value 之间存在 单向一对一关系 ,即通过指定的 Key 总能找到唯一的,确定的 Value

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

public class TestHashMap {
    public static void main(String[] args) {
        //map 在做查找操作时间复杂度是O(1)
        Map map = new HashMap();
        //存储"a"字符串
        map.put(1, "a");
        //覆盖操作
        map.put(1, "b");
        map.put(2, "c");
        System.out.println(map.size());//长度为:2
        //获得1key的value值
        System.out.println(map.get(1));//value值为:b
        //移除
        map.remove(1);
        System.out.println(map.size());//移除后的长度为:1
    }
}

二、HashMap的工作原理

HashMap Map 接口最常用的实现类

封装了哈希表(散列表)数据结构,哈希表是由数组+链表/红黑树 组成的,存储的key和value封装到节点对象中,在存储节点时,先计算key的哈希码值,计算出在数组中的位置,如果数组中该位置有节点,如果不同就存储到后面 的链表中。

HashMap的工作原理:

创建一个HashMap对象时,分配一个负载因子值(是一个百分比值,当哈希表存储的元素相比数组长度达到了负载因子值,将进行扩容操作),默认的负载因子值是0.75 ; 可以指定数组(哈希表)的初始容量,默认的初始容量16 。当调用HashMap的构造器时,数组(哈希表)并没有创建。

当存储一个key-value时,先获得key的hashCode值,用这个值右移16结果和这个值做异或运算获得处理后的int 值,做异或运算的目的为了让这个hashcode计算出的位置在哈希表中能均匀分布,如果哈希表为空或超出了负载 因子值进行扩容,初始创建了长度为16的Node数组(哈希表),用处理后的hash码和数组长度取余运算,获得了哈希表中存储的位置,如果该位置没有节点,则创建一个新的节点存储到该位置 ;如果该位置有节点,判断这个节 点的key和存入的key 的hashCode是否相同并且equals比较是否是true,如果同时满足则替换原节点的value;如果不满足,向节点的链表添加节点,如果链表的长度大于等于7,将链表转为红黑树。其中在哈希表扩容时,要扩容为原长度的一倍,因为尽量保证扩容后原节点的位置和扩容后节点的位置没有大的改变。

三、应用

import java.util.Collection;
import java.util.HashMap;

public class TestHashMap {
    public static void main(String[] args) {
        HashMap<String,Integer> map = new HashMap<String,Integer>();
        map.put("103", 30);
        map.put("102", 20);
        map.put("101", 10);
        System.out.println(map);//{101=10, 102=20, 103=30}
        System.out.println(map.containsKey("1022"));//false
        System.out.println(map.containsValue(10));//true
        //System.out.println(map.getOrDefault("1011", 100));
        map.put("104", null);
        //map.putIfAbsent("104", 40);
        System.out.println(map);//{101=10, 102=20, 103=30, 104=null}
        Collection<Integer> list = map.values();
        System.out.println(list);//[10, 20, 30, null]
       /* Map<String,Person> map = new HashMap<String,Person>();
        map.put("230101199901011234", new Person("tom",23));
        map.put("230101199901011235", new Person("tom2",23));
        System.out.println(map.get("230101199901011234").getName());
        */
    }
}

四、Hashtable和HashMap的区别

HashMap Hashtable Map 接口的两个典型实现类

区别:

Hashtable 是一个古老的 Map 实现类,不建议使用

Hashtable 是一个线程安全的 Map 实现,但 HashMap 是线程不安全的。

Hashtable 不允许使用 null 作为 key value ,而 HashMap 可以

Hashtable是线程安全的,效率低,key和value都不能存储null值

HashMap是线程不安全的,效率高,key和value可以存储null值

五、LinkedHashMap和HashMap的区别

LinkedHashMap是有序的Map集合,封装了一个双向链表,在存储key-value节点时,向两个数据结构存储,分别 存储到链表和哈希表中,在查找时使用哈希表,在遍历时使用链表

LinkedHashMap优点是有序,但缺点是在插入key-value时效率比HashMap低

扩展:红黑树

六、HashSet

无序不可重复的集合,封装了HashMap的集合

ArrayList和HashSet的区别:

import java.util.HashMap;
import java.util.HashSet;

public class TestHashSet {
    public static void main(String[] args) {
        //无序不可重复的(两个key的hashcode和equals相同)
        HashSet<String> set = new HashSet<String>();
        set.add("tom"); //覆盖?没有添加?
        set.add("jack");
        set.add("tom");
        System.out.println(set.size());//长度为:2
        //获得元素?
        set.remove("tom"); //删除元素只能按对象删除
        System.out.println(set);//[jack]
        HashMap<String,Object> map = new HashMap<String,Object>();
        Object obj = new Object();
        map.put("tom", obj);
        map.put("jack", obj);
        map.put("tom", obj);
        System.out.println(map.size());//2
        System.out.println(map.keySet());//[tom, jack]
    }

七、TreeMap/TreeSet

TreeMap是一个可排序的Map集合,是按照key的Comparable接口方法的描述默认排序的

import java.util.Comparator;
import java.util.TreeMap;

public class TestTreeMap {
    public static void main(String[] args) {
        
        class StringLengthComparator implements Comparator<String> {
            @Override
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();
            }
        }
        TreeMap<String, Integer> treeMap = new TreeMap<String,Integer>(new
                StringLengthComparator());
        treeMap.put("ccc", 30);
        treeMap.put("aa", 10);
        treeMap.put("bbbb", 20);
        //结果为已排序的
        System.out.println(treeMap);//{aa=10, ccc=30, bbbb=20}
    }

}

TreeSet封装了TreeMap ,是可排序不可重复的集合

import java.util.Comparator;
import java.util.TreeSet;

public class TestTreeSet {
    public static void main(String[] args) {
        class StringLengthComparator implements Comparator<String> {
            @Override
            public int compare(String o1, String o2) {
                return o1.length()-o2.length();
            }
        }
        TreeSet<String> treeSet = new TreeSet<String>(new StringLengthComparator());
        treeSet.add("ccc");
        treeSet.add("aa");
        treeSet.add("bbbb");
        treeSet.add("aa");
        treeSet.add("ddddd");
        System.out.println(treeSet.size());//长度为:4
        //结果为已排序的
        System.out.println(treeSet);//[aa, ccc, bbbb, ddddd]
    }

}

八、PriorityQueue

是一个优先级顺序的队列,按照默认的Comparable决定优先级的,也可以只能Comparator决定优先级

import java.util.PriorityQueue;

public class TestPriorityQueue {
    public static void main(String[] args) {
        PriorityQueue<Integer> queue = new PriorityQueue<Integer>();
        //存入队列并排序
        queue.add(5);
        queue.add(1);
        queue.add(2);
        queue.add(2);
        //poll:检索并删除此队列的头,如果此队列为空,则返回 null 。
        //结果:这个队列的头,或 null如果这个队列是空的
        System.out.println(queue.poll());//1
        System.out.println(queue.poll());//2
        System.out.println(queue.poll());//2
        System.out.println(queue.poll());//5
    }
}

九、Deque接口

实现类包括LinkedList和ArrayDeque

十、Iterator(迭代器)

迭代器,可以使用迭代器对Collection下的集合进行迭代

Iterator是单向的,在迭代的过程中不能对集合进行修改操作(添加、删除元素操作)

Iterator接口的两个方法:

1. hasNext() : 下一个元素是否存在,迭代器有一个指针

2. next() : 指针向后移动一位,返回当前位置的元素

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();
    Collections.addAll(list, "a","b");
    Iterator<String> it = list.iterator();
    while(it.hasNext()) {
        System.out.println(it.next());
    }
}

调用next之前一定现有hasNext的判断

1.Set集合的迭代:

public static void main(String[] args) {
    //Set接口下的集合 继承了Iterable接口 有iterator方法
    HashSet<String> set = new HashSet<String>();
    Collections.addAll(set, "a","b");
    Iterator<String> it = set.iterator();
    while(it.hasNext()) {
        System.out.println(it.next());
    }
}

2.Map集合的迭代:

通过Map集合的API方法 获得含有所有key的Set集合 或 获得含有所有结点对象的Set集合

 Map的keySet

public static void main(String[] args) {
    HashMap<String,String> map = new HashMap<String,String>();
    map.put("001", "a");
    map.put("002", "b");
    map.put("003", "c");
    //遍历map中所有的key-value
    Set<String> set = map.keySet();
    Iterator<String> it = set.iterator();
    while(it.hasNext()) {
    String key = it.next();
        System.out.println(key+"-"+map.get(key));
    }
}

单向性:

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();
    Collections.addAll(list, "a","b","c","d");
    Iterator<String> it = list.iterator();
    while(it.hasNext()) {
        System.out.println(it.next());
    }
    //重新迭代 没有办法操作迭代器的指针
    it = list.iterator();
    while(it.hasNext()) {
        System.out.println(it.next());
    }
}

并发性:

在迭代过程中不能进行并发的修改,否则抛出

ArrayList<String> list = new ArrayList<String>();
Collections.addAll(list, "a","b","c","d");
/* Iterator<String> it = list.iterator();
    while(it.hasNext()) {
        String s = it.next();
        if("b".equals(s)) {
            list.remove("b");
        }
    }*/
    for(int i = 0;i<list.size();i++) {
        if("b".equals(list.get(i))) {
            list.remove("b");
        }
    }
    System.out.println(list);

Map要删除迭代时符合条件的数据:

public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<String,String>();
        map.put("001", "a");
        map.put("002", "b");
        map.put("003", "c");
        map.put("004", "a");
        map.put("005", "a");
        map.put("006", "d");
        //遍历map中所有的key-value
        Set<String> set = map.keySet();
        Set<String> delKeySet = new HashSet<String>();
        Iterator<String> it = set.iterator();
        while(it.hasNext()) {
            String key = it.next();
            if("a".equals(map.get(key)))
                delKeySet.add(key);
        }
        it = delKeySet.iterator();
        while(it.hasNext()) {
            map.remove(it.next());
        }
        System.out.println(map);
        //Map中 迭代删除 值是"a"的 key-value
        //把值是"a"的key存储在一个集合中
        //再遍历这个集合,调用map.remove(key)
    }

十一、增强型for循环

语法:

基于迭代器的

public static void main(String[] args) {
    ArrayList<String> list = new ArrayList<String>();
    Collections.addAll(list, "a","b","c");
    for(String str:list) {
        System.out.println(str);
    }
}
public static void main(String[] args) {
    //Set接口下的集合 继承了Iterable接口 有iterator方法
    HashSet<String> set = new HashSet<String>();
    Collections.addAll(set, "a","b");
    for(String str:set) {
        System.out.println(str);
    }
}
HashMap<String,String> map = new HashMap<String,String>();
    map.put("001", "a");
    map.put("002", "b");
    map.put("003", "c");
    //遍历map中所有的key-value
    Set<Entry<String,String>> set = map.entrySet();
    for(Entry<String,String> entry:set) {
        System.out.println(entry.getKey()+"-"+entry.getValue());
}
    int[] arr = new int[] {1,2,3};
    for(int i :arr) {
        System.out.println(i);
    }
    int[][] arrs = new int[][] {{4,5},{6,7,8}};
     for(int[] is:arrs){
        for(int i:is){
            System.out.println(i);
        }
     }
举报

相关推荐

0 条评论