集合(Collection)

1. 集合概述

集合、数组都是对数据进行存储操作的结构,简称java容器

数组有些缺点:初始化后长度确定不便于扩展、数组提供的增删改查的方法少、数组存储的数据是有序且可以重复的(无序、不可重复的数据的要求不能满足)

Java 集合类可以用于存储数量不等的多个对象,还可用于保存具有映射关系的关联数组

Java 集合可分为 CollectionMap 两种体系:

Collection接口:单列数据,定义了存取一组对象的方法的集合

  • List:元素有序、可重复的集合。ArrayList、LinkedList、Vector
  • Set:元素无序、不可重复的集合。HashSet、LinkedHashSet、TreeSet

Map接口:双列数据,保存具有映射关系“key-value对”的集合。HashMap、LinkedHashMap、TreeMap、HashTable、Properties


2.Collection接口方法

常用方法1:

@Test
    public void test(){
        Collection coll = new ArrayList();

        //1.boolean add(E e):将元素e添加到集合coll中
        coll.add("AA");
        coll.add(123);
        coll.add(new Person(25, "wkm"));
        coll.add(new Date());

        //2.size():获取添加元素的个数
        System.out.println(coll.size());// 4

        //3.boolean addAll(Collection<? extends E> c): 将c集合中的元素添加到调用addAll的集合
        Collection coll1 = new ArrayList();
        coll1.add(12.34);
        coll1.add(12L);
        coll.addAll(coll1);
        System.out.println(coll.size());//6

        //4.boolean isEmpty(): 判断当前集合是否为空
        System.out.println(coll.isEmpty());//false

        //5.boolean contains(Object o): 判断当前集合是否存在元素o
        System.out.println(coll.contains(123));//true
        System.out.println(coll.contains(new String("AA")));//true
        System.out.println(coll.contains(new Person(25, "wkm")));//false

        //6.boolean containsAll(Collection<?> c):判断当前集合是否存在集合c
        Collection coll2 = Arrays.asList("AA", 123);
        System.out.println(coll.containsAll(coll2));//true
    }

26行输出为true,可以判断contains调用了String重新的equals方法;

27行输出为false,是因为自定义Person类没有重写equals方法;如果重写就是true

因此,对于集合中包含的类,规定要重写equals方法

常用方法2:

    @Test
    public void test2(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
        coll.add(new Person(25, "wkm"));
        coll.add(new String("ABC"));
        coll.add(false);

        //1.boolean remove(Object obj):通过元素的equals方法判断是否是
        //要删除的那个元素。只会删除找到的第一个元素
        System.out.println(coll.remove("ABC"));//true
        System.out.println(coll);//[123, 456, Person{age=25, name='wkm'}, false]

        //2.boolean removeAll(Collection coll):取当前集合的差集
        Collection coll1 = Arrays.asList(123, 4567);
        coll.removeAll(coll1);
        System.out.println(coll);//[456, Person{age=25, name='wkm'}, false]

        //3.boolean retainAll(Collection c):把交集的结果存在当前集合中,不影响c
        Collection coll2 = Arrays.asList(123, 456, 789);
        coll.retainAll(coll2);
        System.out.println(coll);//[456]

        //4.boolean equals(Object obj):当前集合和形参集合是否相等
        Collection coll3 = Arrays.asList(456);
        System.out.println(coll.equals(coll3));//true
    }

常用方法3:

 @Test
    public void test3(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
        coll.add(new Person(25, "wkm"));
        coll.add(new String("ABC"));
        coll.add(false);

        //1.hashCode():获取集合对象的哈希值
        System.out.println(coll.hashCode());//1411494710

        //2.Object[] toArray():转成对象数组
        Object[] arr = coll.toArray();
        for(int i = 0; i < arr.length; i++){
            System.out.println(arr[i]);
            //123
            //456
            //Person{age=25, name='wkm'}
            //ABC
            //false
        }
        //对象数组——>集合:Array.asList
        List<String> strings = Arrays.asList(new String[]{"AA", "BB", "CC"});
        System.out.println(strings);//[AA, BB, CC]
        //注意,传入基本数据类型的数组,数组整体被识别为1个元素
        List<int[]> ints = Arrays.asList(new int[]{12, 34});
        System.out.println(ints);//[[I@573fd745]
        //改正方法1
        List ints2 = Arrays.asList(12, 34);
        System.out.println(ints2);//[12, 34]
        //方法2:换成包装类
        List<Integer> integers = Arrays.asList(new Integer[]{12, 34});
        System.out.println(integers);//[12, 34]
    }

3.Iterator迭代器接口

Collection接口继承了java.lang.Iterable接口,该接口有一个iterator()方法,那么所有实现了Collection接口的集合类都有一个iterator()方法,用以返回一个实现了Iterator接口的对象

Iterator 仅用于遍历集合,Iterator 本身并不提供承装对象的能力。如果需要创建 Iterator 对象,则必须有一个被迭代的集合。

集合对象每次调用iterator()方法都得到一个全新的迭代器对象,默认游标都在集合的第一个元素之前

遍历操作的两个方法:hasNext()/next()

hasNext():判断是否还有下一个元素(初始化迭代器对象时,指针在第一个元素之前)

next():先将指针下移;返回下移后指针指向的集合位置的元素

Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(18, "wkm"));
coll.add(new String("adb"));
coll.add(false);

//iterator():返回迭代器对象,用于集合遍历
Iterator iterator = coll.iterator(); //coll就是被迭代的集合
System.out.println(iterator.hasNext());//true
System.out.println(iterator.next());//123
System.out.println(iterator.next());//456
System.out.println(iterator.next());//Person{age=18, name='wkm'}
System.out.println(iterator.next());//adb
System.out.println(iterator.next());//false
System.out.println(iterator.hasNext());//false:代表没有此迭代器对象没有元素

最推荐的代码编写方式:hasNext()和next()搭配使用

Collection coll = new ArrayList();
coll.add(123);
coll.add(456);
coll.add(new Person(18, "wkm"));
coll.add(new String("adb"));
coll.add(false);

//iterator():返回迭代器对象,用于集合遍历
Iterator iterator = coll.iterator();
while (iterator.hasNext()){
    System.out.println(iterator.next());
}

remove

@Test
    public void test2(){
        Collection coll = new ArrayList();
        coll.add(123);
        coll.add(456);
        coll.add(new Person(18, "wkm"));
        coll.add(new String("adb"));
        coll.add(false);
        Iterator iterator = coll.iterator();

        while(iterator.hasNext()){
            Object obj = iterator.next();
            if(obj.equals("adb")){
                iterator.remove();
                //移除“adb”
            }
        }
        //重新申请全新的迭代器对象,遍历集合查看是否移除“adb”
        Iterator iter2 = coll.iterator();
        while (iter2.hasNext()){
            System.out.println(iter2.next());
        }
        /*123
        456
        Person{age=18, name='wkm'}
        false*/
    }
  1. 此处的remove()是迭代器对象的,与集合对象的remove()不同。
  2. 如果还未调用next()或在上一次调用 next()之后已经调用了 remove 方法,再调用remove都会报IllegalStateException。

使用foreach遍历集合/数组

@Test
public void test3(){
    //遍历集合:for(遍历的元素类型 自定义的局部变量:集合对象)
    Collection coll = new ArrayList();
    coll.add(123);
    coll.add(456);
    coll.add(new Person(18, "wkm"));
    coll.add(new String("adb"));
    coll.add(false);
    for (Object obj : coll){
        System.out.println(obj);
    }

    //遍历数组:for(遍历的元素类型 自定义的局部变量:数组对象)
    int[] nums = new int[]{1, 2, 3, 4};
    for(int i : nums){
        System.out.println(i);
    }
}

4.Collection子接口:List

List接口:存储有序、可重复的数据。包含三个实现类:

  • ArrayList:List接口的主要实现类;底层是通过Object[] elementData实现;线程不安全的、效率高。
  • LinkedList:底层通过双向链表实现,适合用于大量增、删操作。
  • Vector:List接口的古老实现类(jdk1.0);底层是通过Object[] elementData实现;线程安全、效率低。

源码分析

1.ArrayList

jdk7:

ArrayList list = new ArrayList();

底层创建了一个长度为10的Object[]数组ElementData

list.add(11);
...
list.add(21);

扩容:默认情况下扩容为底层数组长度的1.5倍,并将原有数组的数据复制到新的数组中。

建议使用带参构造器:ArrayList list = new ArrayList(int Capacity)

jdk8中的变化:

ArrayList list = new ArrayList();
//此时并未创建长度为10的数组
//源码:private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

第一调用add后才创建了长度为10的数组,并将add的数据添加到ElementData[0];

后续的添加和扩容与jdk7一样。

2.LinkedList源码

jdk7与8中没有较大变化

LinkedList list = new LinkedList();

内部声明了Node类型的first和last属性,默认值为null;

调用list.add(xxx),添加元素的源代码:void linkLast(E e),过程相当于在链表末尾添加新节点

3.Vector

jdk7和jdk8初始化Vector对象时默认底层数组长度为10,扩容后默认为原来大小的2倍;

List接口常用方法

void add(int index, Object ele):在index位置插入ele元素

boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来

Object get(int index):获取指定index位置的元素

int indexOf(Object obj):返回obj在集合中首次出现的位置

int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置

Object remove(int index):移除指定index位置的元素,并返回此元素

Object set(int index, Object ele):设置指定index位置的元素为ele

List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合

package com.coderwkm.java;

import org.junit.Test;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author Wkm
 * @date 2023-01-28 下午 6:32
 * @description: List常用方法
 */
public class ListTest {
    @Test
    public void test1(){
        ArrayList list = new ArrayList();
        list.add(123);
        list.add(456);
        list.add("Tom");
        list.add(new Person(25, "wkm"));
        System.out.println(list);
        //[123, 456, Tom, Person{age=25, name='wkm'}]

        //1.void add(int index, Object ele):在index位置插入ele元素
        list.add(0, 456);
        System.out.println(list);
        //[456, 123, 456, Tom, Person{age=25, name='wkm'}]

        //2.boolean addAll(int index, Collection eles):从index位置开始将eles中的所有元素添加进来
        List list1 = Arrays.asList("BBB", 11, 54);
        list.addAll(3, list1);
        System.out.println(list);
        //[456, 123, 456, BBB, 11, 54, Tom, Person{age=25, name='wkm'}]

        //3.Object get(int index):获取指定index位置的元素
        System.out.println(list.get(2));//456

        //4.int indexOf(Object obj):返回obj在集合中首次出现的位置
        System.out.println(list.indexOf(456));//0

        //5.int lastIndexOf(Object obj):返回obj在当前集合中末次出现的位置
        System.out.println(list.lastIndexOf(456));//2

        //6.Object remove(int index):移除指定index位置的元素,并返回此元素
        System.out.println(list.remove(5));//54
        System.out.println(list);
        //[456, 123, 456, BBB, 11, Tom, Person{age=25, name='wkm'}]

        //7.Object set(int index, Object ele):设置指定index位置的元素为ele
        System.out.println(list.set(0, "ABCF"));//456
        System.out.println(list);
        //[ABCF, 123, 456, BBB, 11, Tom, Person{age=25, name='wkm'}]

        //8.List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合
        System.out.println(list.subList(3, 5));//[BBB, 11]
    }
}
  1. 关于方法4、5, 如果obj在集合中未找到,返回-1(java中很多方法都是如此)
  2. 注意方法6:remove(),是移除指定索引的元素,并且返回被移除的元素;Collection接口的^ 1
  3. 方法7:是用ele替换index处的值,返回的也是被替换的原始值
  4. 方法8:左闭右开

list常用方法:

  • 增:add()/addAll()/add(int index, Object ele)
  • 删:remove(int index)/remove(Object obj)
  • 改:set(int index, Object ele)
  • 查:get(int index)
  • 长度:size()
  • 遍历:迭代器循环/foreach/普通的for循环

5.Collection子接口:Set

Set接口:存储无序、不可重复的数据。包括:

  • HashSet:Set的主要实现类;线程不安全;可以存储null
  • LinkedHashSet:HashSet子类,遍历内部数据时可以按照添加的顺序遍历;
  • TreeSet:可以按照添加对象的属性进行排序

1.HashSet

以HashSet为例说明Set接口的无序、不可重复的特点:

package com.settest.java;

import org.junit.Test;

import java.util.HashSet;
import java.util.Iterator;

/**
 * @author Wkm
 * @date 2023-01-29 下午 11:18
 * @description: 理解Set的无序、不可重复特性
 *
 * 无序:添加的元素在底层数组的存储顺序是按照元素的Hash值存储
 * 不可重复:相同的元素只能添加一个(相同:equals的返回值是true)
 */
public class SetTest {
    @Test
    public void test1(){
        HashSet set = new HashSet();
        set.add(123);
        set.add(456);
        set.add("AA");
        set.add("BB");
        set.add(new User("wkm", 25));
        set.add(new User("wkm", 25));
        set.add(123);

        /*
            1.无序:不是按照添加的顺序显示的
            AA BB User{name='wkm', age=25} 456 123
            2.不可重复:
                添加了两个123,但只显示1个;
                未重写equals和hashCode之前,显示两个User对象;重写后只显示一个
         */
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
    }
}

以HashSet为例说明添加元素的过程

  1. 当向 HashSet 集合中存入一个元素时,HashSet 会调用该对象的 hashCode() 方法来得到该对象的 hashCode 值,然后根据 hashCode 值,通过某种散列函数决定该对象在 HashSet 底层数组中的存储位置。
  2. 如果两个元素的hashCode()值相等,会再继续调用equals方法,如果equals方法结果 为true,添加失败;如果为false,那么会保存该元素,但是该数组的位置已经有元素了, 那么会通过链表的方式继续链接(jdk7新元素添加数组中并指向旧元素,jdk8相反,即“七上八下”)。
  3. 如果两个元素的 equals() 方法返回 true,但它们的 hashCode() 返回值不相等,hashSet 将会把它们存储在不同的位置,但依然可以添加成功。

总结:先hashCode再equals!

关于Set需要注意:

  1. Set接口没有新定义的方法,使用的都是Collection接口中的方法。
  2. 向Set中添加的数据,一定要在所在的类重写 hashCode() 和 equals()
  3. 重写的 hashCode() 和 equals() 尽可能保持一致性:相等的对象(equals() 方法比较返回 true)必须具有相等的散列码 (hashCode()方法的返回值)
  4. 对象中用作 equals() 方法比较的 Field,都应该用来计算 hashCode 值。
package com.settest.java;

/**
 * @author Wkm
 * @date 2023-01-29 下午 11:51
 * @description: 自定义User(用于添加到Set)
 */
public class User {
    private String name;
    private int age;	
    //构造器、get、set.....
    
    //idea重写:
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User user = (User) o;

        if (age != user.age) return false;
        return name != null ? name.equals(user.name) : user.name == null;
    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }
}

2.LinkedHashSet

    @Test
    public void test2(){
         /*
        输出结果是按添加的顺序显示:123 456 AA BB User{name='wkm', age=25}
        LinkedHashSet是HashSet的子类,在添加数据的同时维护了两个引用记录添加顺序;
        因此,对于频繁遍历的操作,效率高于HashSet
        */
        Set set = new LinkedHashSet();
        set.add(123);
        set.add(456);
        set.add("AA");
        set.add("BB");
        set.add(new User("wkm", 25));
        set.add(new User("wkm", 25));
        set.add(123);

        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }

    }

3.TreeSet

TreeSet:可以按照添加对象的属性进行排序,因此添加的元素不可以是不同类的对象

TreeSet 是 SortedSet 接口的实现类,TreeSet 可以确保集合元素处于排序状态。

TreeSet底层使用红黑树结构存储数据 。新增的方法如下: (了解)

  • Comparator comparator()

  • Object first()

  • Object last()

  • Object lower(Object e)

  • Object higher(Object e)

  • SortedSet subSet(fromElement, toElement)

  • SortedSet headSet(toElement)

  • SortedSet tailSet(fromElement)

TreeSet 两种排序方法:自然排序和定制排序。默认情况下,TreeSet 采用自然排序。

package com.settest.java;

import org.junit.Test;

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

/**
 * @author Wkm
 * @date 2023-01-30 下午 4:43
 * @description: TreeSetTest
 * 对于TreeSet:
 *      1. 添加到数据,必须是相同类的数据
 *      2. 用到先前的两种排序方式:自然排序/定制排序
 *      3. 自然排序中,比较两个对象是否相等的依据:compareTo()是否返回0。而非equals()
 */
public class TreeSetTest {
    //1.自然排序测试
    @Test
    public void test1(){
        TreeSet set = new TreeSet();
        set.add(new User("wkm", 25));
        set.add(new User("yyy", 25));
        set.add(new User("mm", 0));
        set.add(new User("mm", 1));
        set.add(new User("wy", 5));

        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        /*
        1.如果没有实现某种排序:
        java.lang.ClassCastException: com.settest.java.User cannot be cast to java.lang.Comparable

        2.如果在compareTo中只按照name属性排序,此例中有两个name相同的对象mm但age不一样
        输出结果:
            User{name='mm', age=0}
            User{name='wkm', age=25}
            User{name='wy', age=5}
            User{name='yyy', age=25}

        3.在排序name的基础上再对aga进行排序:
            User{name='mm', age=0}
            User{name='mm', age=1}
            User{name='wkm', age=25}
            User{name='wy', age=5}
            User{name='yyy', age=25}
         */
    }

    //2.定制排序测试
    @Test
    public void test2(){
        //step1:创建comparator对象
        Comparator com = new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                if(o1 instanceof User && o2 instanceof User){
                    User user1 = (User)o1;
                    User user2 = (User)o2;
                    //按年龄排序
                    int compareValue = Integer.compare(user1.getAge(), user2.getAge());
                    if(compareValue != 0){
                        return compareValue;
                    }
                    return user1.getName().compareTo(user2.getName());
                }
                throw new RuntimeException("比较的对象类型不匹配");
            }
        };

        //step2:将step1中的Comparator对象传入TreeSet带参构造器(先前是传入sort方法)
        TreeSet set = new TreeSet(com);
        set.add(new User("wkm", 25));
        set.add(new User("yyy", 25));
        set.add(new User("mm", 0));
        set.add(new User("mm", 1));
        set.add(new User("wy", 5));

        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        /*
            User{name='mm', age=0}
            User{name='mm', age=1}
            User{name='wy', age=5}
            User{name='wkm', age=25}
            User{name='yyy', age=25}
         */
    }
}


//关于User类的自然排序
package com.settest.java;

/**
 * @author Wkm
 * @date 2023-01-29 下午 11:51
 * @description: 自定义User(用于添加到Set)
 */
public class User implements Comparable{
    private String name;
    private int age;
	
    //构造器、get、set、toString、hashCode、equals...
    
    @Override
    public int compareTo(Object o) {
        if(o instanceof User){
            //按name排序
            User user = (User)o;
            int comparevalue = this.name.compareTo(user.name);
            if (comparevalue != 0){
                return comparevalue;
            }
            //再按age排序
            return Integer.compare(this.age, user.age);
        }
        throw new RuntimeException("比较的对象类型不匹配");
    }
}

6.Map接口

1.概述

Map:双列数据,存储key-value键值对

Map的分类:

image-20230130235016645

  • HashTable:古老实现类;线程安全、效率低;不能存储null的key和value。
    • Properties:常用来处理配置文件;key和value都是String类型。
  • HashMap:Map的主要实现类;线程不安全、效率高;可存储null的key和value。
    • LinkedHashMap:遍历map元素时可按照添加顺序实现遍历(在HashMap底层结构基础上添加了一对记录指向前后元素的指针)。
  • TreeMap:按照添加的key-value进行排序,实现排序遍历。(根据key进行自然排序/定制排序;红黑树)

关于Map结构:

  • Map中的key:无序、不可重复,用Set存(XXSet与XXMap对应)。
  • Map中的value:无序、可重复,用Collection存。
  • Map中的entry:一个key-value构成了一个entry对象;entry对象无序、不可重复,使用Set存储所有的entry。

对于key:若是HashMap,key所在的类要重写 equals() 和 hashCode() ; 若是TreeSet,自然排序/定制排序。

对于value:value所在的类重写 equals()。


2.HashMap底层实现原理

①jdk7:
HashMap map = new HashMap();

此时,底层创建了长度为16的数组:Entry[] table

//....经过若干操作
map.put(key1, value1);

首先调用key1所在类的hashCode()(实际上是源码中的 hash(key) 方法)计算key1的hash值,此hash值经过某种算法计算( indexFor() )后,得到在Entry数组中的存放位置。

  • case1:如果此位置上的数据为空,key1-value1添加成功;

  • 如果此位置上的数据不为空(此位置存有一/多个数据,以链表形式存储),比较key1和已经存在数据的hash值:

    • case2:两者的hash值不同:key1-value1添加成功;
    • key1的hash值和某个存在的数据(key2-value2)的hash相同:调用key1所在类的equals():key.equals(key2)
      • case3:返回false: key1-value1添加成功;
      • 返回true:用value替换value2;

case2和case3:key1-value1与原来的数据以链表方式存储(头插/尾插)

扩容问题:当超出threshhold值且要存放的位置非空,扩容为原始的2倍, 并将原始的数据复制过来。

②jdk8的变化
  1. HashMap map = new HashMap();
    

    此时并未直接创建长度为16的数组,而是在首次向此map中调用put时才创建。

  2. jdk8的底层数组:Node[]

  3. jdk7底层结构:数组+链表,jdk8是链表+数组+红黑树

几个常量:

  • DEFAULT_INITIAL_CAPACITY : HashMap的默认容量,16
  • DEFAULT_LOAD_FACTOR:HashMap的默认加载因子,0.75
  • threshold:扩容的临界值,等于容量*填充因子:16 * 0.75 = 12
  • TREEIFY_THRESHOLD:Bucket中链表长度大于该默认值,转化为红黑树:8
  • MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量,64

3.LinkedHashMap

LinkedHashMap重写了父类的的 NewNode()

HashMap中的内部类:Node

static class Node<K,V> implements Map.Entry<K,V> {
    final int hash;
    final K key;
    V value;
    Node<K,V> next;
}

LinkedHashMap中的内部类:Entry

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);
    }
}

4.Map常用方法

package com.HashMap.java;

import org.junit.Test;

import java.util.*;

/**
 * @author Wkm
 * @date 2023-01-31 上午 12:04
 * @description: TODO
 */
public class MapTest {

     //常用方法1. 添加、删除、修改操作
    @Test
    public void test1(){
        HashMap map = new HashMap();
        //1. Object put(Object key,Object value):将指定key-value添加到(或修改)当前map对象中
        map.put("AA", 123);
        map.put("BB", 456);
        map.put("CC", 789);
        //根据源码,此时123被替换为456
        map.put("AA", 456);
        System.out.println(map);//{AA=456, BB=456, CC=789}

        //2. void putAll(Map m):将m中的所有key-value对存放到当前map中
        HashMap map1 = new HashMap();
        map1.put(123, 456);
        map1.put(456, "DD");
        System.out.println("map1:"+ map1);// map1:{456=DD, 123=456}
        map.putAll(map1);
        System.out.println("map:" + map);// map:{AA=456, BB=456, CC=789, 456=DD, 123=456}

        //3. Object remove(Object key):移除指定key的key-value对,并返回value
        Object rec = map.remove(456);
        System.out.println(rec);// DD
        System.out.println("map:" + map);// map:{AA=456, BB=456, CC=789, 123=456}

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

    //常用方法2. 元素查询的操作:
    @Test
    public void test2(){
        
        //1. Object get(Object key):获取指定key对应的value
        HashMap map = new HashMap();
        map.put("AA", 123);
        map.put("BB", 456);
        map.put("CC", 789);
        Object aa = map.get("AA");
        System.out.println(aa);//123
        System.out.println(map);//{AA=123, BB=456, CC=789}

        //2. boolean containsKey(Object key):是否包含指定的key
        System.out.println(map.containsKey("AA"));//true
        System.out.println(map.containsKey("DD"));//false

        //3. boolean containsValue(Object value):是否包含指定的value
        System.out.println(map.containsValue("789"));//false
        System.out.println(map.containsValue(789));//true

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

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

        //6. boolean equals(Object obj):判断当前map和参数对象obj是否相等
        HashMap map2 = new HashMap();
        map2.put("AA", 123);
        map2.put("BB", 456);
        System.out.println(map.equals(map2));//false
        map2.put("CC", 789);
        System.out.println(map.equals(map2));//true
    }

    @Test
    public void test3(){
        //1. Set keySet():返回所有key构成的Set集合
        HashMap map = new HashMap();
        map.put("AA", 123);
        map.put("BB", 456);
        map.put("CC", 789);
        Set set = map.keySet();
        Iterator iterator = set.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
            // AA
            // BB
            // CC
        }

        //2. Collection values():返回所有value构成的Collection集合
        Collection values = map.values();
        for(Object obj : values){
            System.out.println(obj);
            /*
            123
            456
            789
            !!!可以看到通过方法1和方法2遍历的key和value的顺序是一一对应的
            */
        }

        //3. Set entrySet():返回所有key-value对构成的Set集合
        Set set1 = map.entrySet();
        Iterator iterator1 = set1.iterator();
        while (iterator1.hasNext()){
            //将entrySet()获得的元素墙砖成Map中的Entry
            Map.Entry entry = (Map.Entry)iterator1.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
            /*
            AA--->123
            BB--->456
            CC--->789
            !!还可以通过前两个方法先获取keySet,再通过get(Object key)取value
             */
        }

    }
}

5.TreeMap

与TreeSet类似,需要注意:

  1. 添加的key必须是同一个类创建的对象。
  2. 按key排序:自然排序/定制排序。
package com.HashMap.java;

import org.junit.Test;

import java.util.*;

/**
 * @author Wkm
 * @date 2023-01-31 下午 9:06
 * @description: 此处添加的User自定义类与TreeSet测试的User类相同
 */
public class TreeSetTest {
    //自然排序
    @Test
    public void test1(){
        TreeMap treeMap = new TreeMap();
        treeMap.put(new User("wkm", 25), 93);
        treeMap.put(new User("yyy", 24), 95);
        treeMap.put(new User("mm", 0), 99);
        treeMap.put(new User("wy", 1), 100);

        Set set1 = treeMap.entrySet();
        Iterator iterator1 = set1.iterator();
        while (iterator1.hasNext()){
            Map.Entry entry = (Map.Entry)iterator1.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
        /*
        User{name='mm', age=0}--->99
        User{name='wkm', age=25}--->93
        User{name='wy', age=1}--->100
        User{name='yyy', age=24}--->95
         */
    }


    //定制排序
    @Test
    public void test2(){
        TreeMap treeMap = 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("比较的对象类型不匹配");
            }
        });

        treeMap.put(new User("mm", 0), 99);
        treeMap.put(new User("wkm", 25), 93);
        treeMap.put(new User("yyy", 24), 95);
        treeMap.put(new User("wy", 1), 100);

        Set set1 = treeMap.entrySet();
        Iterator iterator1 = set1.iterator();
        while (iterator1.hasNext()){
            Map.Entry entry = (Map.Entry)iterator1.next();
            System.out.println(entry.getKey() + "--->" + entry.getValue());
        }
        /*
        User{name='mm', age=0}--->99
        User{name='wy', age=1}--->100
        User{name='yyy', age=24}--->95
        User{name='wkm', age=25}--->93
         */
    }
}

6.Properties

  • Properties 类是 Hashtable 的子类,该对象用于处理属性文件
  • 由于属性文件里的 key、value 都是字符串类型,所以 Properties 里的 key 和 value 都是字符串类型
  • 存取数据时,建议使用setProperty(String key,String value)方法和getProperty(String key)方法
package com.HashMap.java;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.Properties;

public class PropertiesTest {
    public static void main(String[] args) throws Exception {
        Properties properties = new Properties();

        FileInputStream fileInputStream = new FileInputStream("jdbc.properties");
        properties.load(fileInputStream);//加载流对应的文件

        String name = properties.getProperty("user");
        String password = properties.getProperty("password");
        System.out.println("user: " + name + ", password: " + password);
        //user: wkm王杨, password: 123wkm
    }
}

注意几点:

  1. 在idea工程中创建properties文件:右键工程名称——>New,如下图所示:

    如果创建File,需要自动补全文件后缀**.properties**

    image-20230131213159677
  2. properties文件内容如下:

    user=wkm王杨
    password=123wkm
    

    注意”=“与字符之间不要保留空格!

  3. 测试代码输出的乱码问题

    image-20230131214429961

7.Collections工具类

package com.HashMap.java;

import com.HashMap.exer.test1;
import org.junit.Test;

import java.util.*;

/**
 * @author Wkm
 * @date 2023-01-31 下午 9:52
 * @description: Collections常用方法测试
 *
 * 一、排序操作:(均为static方法)
 * 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 {
    //一、排序操作:(均为static方法)
    @Test
    public void test1(){
        ArrayList list = new ArrayList();
        list.add(5);
        list.add(6);
        list.add(7);
        //1. reverse(List):反转 List 中元素的顺序
        Collections.reverse(list);
        System.out.println(list);//[7, 6, 5]

        //2. shuffle(List):对 List 集合元素进行随机排序
        Collections.shuffle(list);
        System.out.println(list);//[6, 5, 7]

        //3. sort(List):根据元素的自然顺序对指定 List 集合元素按升序排序
        list.add(3);
        Collections.sort(list);
        System.out.println(list);//[3, 5, 6, 7]

        //4. sort(List,Comparator):根据指定的 Comparator 产生的顺序对 List 集合元素进行排序
        Comparator com = new Comparator(){
            @Override
            public int compare(Object o1, Object o2) {
                //逆序
                int num1 = (Integer)o1;
                int num2 = (Integer)o2;
                return num2 > num1 ? 1 : -1;
            }
        };
        Collections.sort(list, com);
        System.out.println(list);//[7, 6, 5, 3]

        //5. swap(List,int, int):将指定 list 集合中的 i 处元素和 j 处元素进行交换
        Collections.swap(list, 0, 2);
        System.out.println(list);//[5, 6, 7, 3]
    }

    //二、查找、替换:
    @Test
    public void test2(){
        //1. Object max(Collection):根据元素的自然顺序,返回给定集合中的最大元素
        ArrayList list = new ArrayList();
        list.add(5);
        list.add(6);
        list.add(7);
        System.out.println(Collections.max(list));// 7

        //2. Object max(Collection,Comparator):根据 Comparator 指定的顺序,返回给定集合中的最大元素
        Comparator com = new Comparator(){
            @Override
            public int compare(Object o1, Object o2) {
                //逆序
                int num1 = (Integer)o1;
                int num2 = (Integer)o2;
                return num2 > num1 ? 1 : -1;
            }
        };
        System.out.println(Collections.max(list, com));// 5

        //3. Object min(Collection)
        //4. Object min(Collection,Comparator)

        //5. int frequency(Collection,Object):返回指定集合中指定元素的出现次数
        list.add(5);
        list.add(0);
        System.out.println(Collections.frequency(list, 5));// 2
        System.out.println(list);//[5, 6, 7, 5, 0]

        //6. void copy(List dest,List src):将src中的内容复制到dest中
        //注意下一行的写法技巧
        List dest = Arrays.asList(new Object[list.size()]);
        Collections.copy(dest, list);
        System.out.println(dest);//[5, 6, 7, 5, 0]

        //7. boolean replaceAll(List list,Object oldVal,Object newVal):
        // 使用新值替换List对象的所有旧值
        Collections.replaceAll(list, 5, 6);
        System.out.println(list);//[6, 6, 7, 6, 0]
    }
}

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

Enumeration 接口是 Iterator 迭代器的 “古老版本”

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值