Java-day24(java集合:Map接口)

Map接口

在这里插入图片描述
在这里插入图片描述

一、Map实现类的接口
|- Map:双列数据,储存key-value对的数据 → 类似高中的函数:y = f(x)

|-- HashMap: 作为Map 的主要实现类;线程不安全,效率高;储存null 的key 和 value。
在这里插入图片描述
|---- LinkedHashMap: 保证在遍历Map元素时,可以按照添加的顺序实现遍历。
原因: 在原有的HashMap底层结构基础上,添加了一对指针,指向前一个和后一个元素。
对于频繁的遍历操作,此类执行效率高于HashMap。

HashMap 的底层:数组+链表(JDK7之前)
数组+链表+红黑树(JDK8)

|-- TreeMap: 保证按照添加的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序。底层使用红黑树。

|-- Hashtable: 作为古老的实现类:线程安全的,效率低;不能储存null 的key 和 value。
|---- Properties: 常用来处理配置文件。key和value都是String类型。

二、Map结构的理解:
Map中的key:无序的、不可重复的。使用Set储存所有的key → key所在的类要重写equals( ) 和 hashCode( ) (以HashMap为例)
Map中的value:无序的、可重复的,使用Collection储存所有的value → value所在的类要重写equals( )
Map中的entry:无序的、不可重复的,使用Set 储存所有的entry

三、HashMap的底层实现原理:
我们以 JDK7 为例说明:
HashMap map = new HashMap( ):
在实例化以后,底层创建类长度的为16的一维数组Entry[ ] table.
假设现在是执行了多次put过后,然后我们添加 (key1, value1 )…
map.put(key1,value1):
首先,调用key1所在类的hashCode( ) 计算 key1 哈希值,此哈希值经过某种算法以后, 得到在Entry数组中的存放位置(相同位置的元素哈希值不一定一样)。会有多种情况:

情况一: 如果此位之上的数据为空,此时的key1-value1 添加成功。

如果此位置上的数据不为空,(意味着此位置上存在一个或多个数据(以链表形式存在)),比较key1和已经存在的一个或多个数据的哈希值:
情况二:
如果key1的哈希值与已经存在的数据的哈希值都不相同,此时可以key1-value1添加成功。

如果key1的哈希值和已经存在的某一个数据(key2-value2)的哈希值相同,继续比较:调用key1所在类的equals (key2 )
情况三: 如果equals( )返回false:此时key1- value1添加成功。
如果equals( )返回true:使用value1替换value2(Set中equals返回true直接就是添加失败)

补充:关于情况二 和情况三 :此时key1 - value1和的数据以链表的方式存储。
在不断的添加过程中,会涉及到扩容问题,当超出临界值时(或放置的位置是为非空时)默认的扩容方式:扩容为原来容量的两倍,并将原有的数据复制过来。

JDK8 相较于JDK7在底层实现方面的不同:

  1. new HashMap( ):底层没有创建一个长度为16 的数组
  2. JDK 8 底层的数组是:Node[ ] ,而非Entry[ ]
  3. 首次调用put( ) 方法时,底层创建长度为16的数组
  4. JDK7底层结构只有:数组+链表。JDK8中底层结构:数组+链表+红黑树。
    4.1 形成莲表示,七上八下(JDK7:新的元素指向旧元素。JDK8:旧的元素指向新的元素)
    在这里插入图片描述

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

四、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中定义的方法
在这里插入图片描述

HashMap测试:

添加、删除、修改操作:

//Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
//void putAll(Map m):将m中的所有key-value对存放到当前map中 
//Object remove(Object key):移除指定key的key-value对,并返回value 
//void clear():清空当前map中的所有数据
 @Test
    public void test3(){
        Map map = new HashMap();
        //Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
        map.put("AA",123);
        map.put("45",125);
        map.put("BB",156);
        map.put("AA",187);//相当于修改
        map.put(45,123);

        System.out.println(map);//{AA=187, BB=156, 45=125, 45=123}        System.out.println(map);//

        //void putAll(Map m):将m中的所有key-value对存放到当前map中 
        Map map1 = new HashMap();
        map1.put("cc",123);
        map1.put("dd",345);
        map.putAll(map1);
        System.out.println(map);//{AA=187, BB=156, cc=123, dd=345, 45=125, 45=123}

        //Object remove(Object key):移除指定key的key-value对,并返回value 
        Object value = map.remove("cc");
        System.out.println(value);//123
        System.out.println(map);//{AA=187, BB=156, dd=345, 45=125, 45=123}

        //void clear():清空当前map中的所有数据
        map.clear();
        System.out.println(map.size());//0
        System.out.println(map);//{}
        System.out.println(map.isEmpty());//true
    }

元素查询的操作:

//Object get(Object key):获取指定key对应的value
//boolean containsKey(Object key):是否包含指定的key
//boolean containsValue(Object value):是否包含指定的value
//int size():返回map中key-value对的个数
//boolean isEmpty():判断当前map是否为空
//boolean equals(Object obj):判断当前map和参数对象obj是否相同
public class MapTest1 {
    @Test
    public void test4() {
        HashMap map = new HashMap();
        map.put("aa", 123);
        map.put("cc", 124);
        map.put(45, 123);
        System.out.println(map);

        //Object get(Object key):获取指定key对应的value
        System.out.println(map.get(45));//123

        //boolean containsKey(Object key):是否包含指定的key
        boolean isExist = map.containsKey("aa");
        System.out.println(isExist);//true

        //boolean containsValue(Object value):是否包含指定的value
        isExist = map.containsValue(123);
        System.out.println(isExist);//true 这里有两个123找到一个就不会往下找了 直接显示true

        //int size():返回map中key-value对的个数
        int num = map.size();
        System.out.println(num);//3

        //boolean isEmpty():判断当前map是否为空
        boolean isEmpty = map.isEmpty();
        System.out.println(isEmpty);//false

        //boolean equals(Object obj):判断当前map和参数对象obj是否相同

    }
}

元视图操作的方法:

//Set keySet():返回所有key构成的Set集合
//Collection values():返回所有value构成的Collection集合
//Set entrySet():返回所有key-value对构成的Set集合
public class MapTest2 {
    @Test
    public void test() {
        Map map = new HashMap();
        map.put("aa", 123);
        map.put("bb", 145);
        map.put(45, 123);

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

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

        //Set entrySet():返回所有key-value对构成的Set集合
        Set set1 = map.entrySet();
        for (Object obj1 : set1) {
            System.out.println(obj1);//aa=123 bb=145 45=123
        }
    }

}

总结:
添加:put(Object key, Object value)
删除:remove(Object key)
修改:put(Object key, Object value)
查询:get(Object key)
长度:size( )
遍历:keySet( ) / values( ) / entrySet( )

TreeMap测试:

在这里插入图片描述

public class TreeMapTest {

    //向TreeMap中添加key-value,要求key必须是由同一个类创建的对象
    //因为要按照key进行排序:自然排序 、定制排序
    //自然排序
    @Test
    public void test1(){
        TreeMap map = new TreeMap();
        User u1 = new User("Tom",23);
        User u2 = new User("Jerry",32);
        User u3 = new User("Jack",20);
        User u4 = new User("Rose",18);

        map.put(u1,98);
        map.put(u2,89);
        map.put(u3,76);
        map.put(u4,100);

        Set entrySet = map.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()){
            Object obj = iterator1.next();
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + "---->" + entry.getValue());

        }
    }

    //定制排序
    @Test
    public void test2(){
        TreeMap map = new TreeMap(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());
                }
                throw new RuntimeException("输入的类型不匹配!");
            }
        });
        User u1 = new User("Tom",23);
        User u2 = new User("Jerry",32);
        User u3 = new User("Jack",20);
        User u4 = new User("Rose",18);

        map.put(u1,98);
        map.put(u2,89);
        map.put(u3,76);
        map.put(u4,100);

        Set entrySet = map.entrySet();
        Iterator iterator1 = entrySet.iterator();
        while (iterator1.hasNext()){
            Object obj = iterator1.next();
            Map.Entry entry = (Map.Entry) obj;
            System.out.println(entry.getKey() + "---->" + entry.getValue());

        }
    }
}

Properties

在这里插入图片描述
我们先设置配置文件(文件名:jdbc.properties):
在这里插入图片描述
PropertiesTest类:

public class PropertiesTest {

    //Properties:常用来处理配置文件。Key和value都是String类型
    public static void main(String[] args) throws Exception {
        Properties pros = new Properties();//Properties的使用

        FileInputStream fis = new FileInputStream("jdbc.properties");
        pros.load(fis);
        String name = pros.getProperty("name");
        String password = pros.getProperty("password");

        System.out.println("name =" + name + ",password = " + password);

    }
}

Collections工具类:操作集合的工具类

ps:操作数组的工具类:Arrays
在这里插入图片描述
在这里插入图片描述

//    reverse(List):反转 List 中元素的顺序
//    shuffle(List):对 List 集合元素进行随机排序
//    sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
//    sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
//    swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
//
//    Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
//    Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
//    Object min(Collection)
//    Object min(Collection,Comparator)
//    int frequency(Collection,Object):返回指定集合中指定元素的出现次数
//    void copy(List dest,List src):将src中的内容复制到dest中
//    boolean replaceAll(List list,Object oldVal,Object newVal):使用新值替换 List 对象的所有旧值

public class CollectionsTest {
    @Test
    public void test(){
        List list = new ArrayList();
        list.add(123);
        list.add(43);
        list.add(765);
        list.add(-97);
        list.add(0);

        System.out.println(list);
        //reverse(List):反转 List 中元素的顺序
        //Collections.reverse(list);//[0, -97, 765, 43, 123]

        //shuffle(List):对 List 集合元素进行随机排序
        Collections.shuffle(list);//[-97, 765, 43, 123, 0]

        //sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
        Collections.sort(list);//[-97, 0, 43, 123, 765]

        //swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
        Collections.swap(list,1,2);//[-97, 43, 0, 123, 765]

        //int frequency(Collection,Object):返回指定集合中指定元素的出现次数
        System.out.println(Collections.frequency(list, 765));//1

        System.out.println(list);
    }


    @Test
    //void copy(List dest,List src):将src中的内容复制到dest中
    public void test2(){
        List list = new ArrayList();
        list.add(123);
        list.add(43);
        list.add(765);
        list.add(-97);
        list.add(0);

        //目的集合的长度需要大于原集合的长度,不然会报异常
        //List dest = new ArrayList();
        //Collections.copy(dest,list);//IndexOutOfBoundsException: Source does not fit in dest

        List dest = Arrays.asList(new Object[list.size()]);
        Collections.copy(dest,list);
        System.out.println(dest.size());//5

        System.out.println(dest);//[123, 43, 765, -97, 0]
    }

}

Collections常用方法:同步控制

Collections 类中提供了多个 synchronizedXxx() 方法,该方法可使将指定集 合包装成线程同步的集合,从而可以解决多线程并发访问集合时的线程安全 问题

//返回的list1即为线程安全的list
List list1 = Collections.sychronizedList(list);

每日一练:

1. Map存储数据的特点是什么?并指明key,value,entry存储数据的特点。
双列数据,存储key-value对数据。
key:无序的、不可重复的→ Set存储
value:无序的、可重复的 → Collection存储
key-value:无序的、不可重复 → Set存储

2. 描述HashMap的底层实现原理(jdk 8版)

首先通过哈希值计算得到一个位置,如果位置上没有元素就添加成功
如果位置上有元素,那么就去比较这个位置上的所有元素的哈希值看是否一致
如果都不一致,直接添加成功。
如果存在有元素(key2)与其哈希值一致的情况:
我们在通过重写以后equals(key2) 去比较他们的内容,如果返回false就替换key2,即添加成功
如果返回true,就添加失败。

3. Map中常用实现类有哪些?各自有什么特点?

|-- HashMap: 作为Map 的主要实现类;线程不安全,效率高;储存null 的key 和 value。
|---- LinkedHashMap: 保证在遍历Map元素时,可以按照添加的顺序实现遍历。对于频繁的遍历操作,此类执行效率高于HashMap。
|-- TreeMap: 保证按照天健的key-value对进行排序,实现排序遍历。此时考虑key的自然排序或定制排序。底层使用红黑树。
|-- Hashtable: 作为古老的实现类:线程安全的,效率低;不能储存null 的key 和 value。
|---- Properties: 常用来处理配置文件。key和value都是String类型。

4. 如何遍历Map中的key-value对,代码实现

//Set keySet():返回所有key构成的Set集合
//Collection values():返回所有value构成的Collection集合
//Set entrySet():返回所有key-value对构成的Set集合
public class MapTest2 {
    @Test
    public void test() {
        Map map = new HashMap();
        map.put("aa", 123);
        map.put("bb", 145);
        map.put(45, 123);

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

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

        //Set entrySet():返回所有key-value对构成的Set集合
        Set set1 = map.entrySet();
        for (Object obj1 : set1) {
            System.out.println(obj1);//aa=123 bb=145 45=123
        }
    }

}

在这里插入图片描述

5. Collection和Collections的区别?
Collection:单列集合的一个接口,内部定义了一些规范,常用的有List、Set接口
Collections:是一个操作 Set、List 和 Map 等集合的工具类

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值