集合常用接口及实现类

集合

单列集合 Collection (接口)
双列集合 Map (接口)

集合:集合是java中提供的一种容器,可以用来存储多个数据。

集合和数组既然都是容器,它们有什么区别呢?

  • 数组的长度是固定的!可以存放任意类型的数据基本类型+引用类型),只不过,我们在开发的时候经常将同一类型的数据放入一个数组!【它的操作非常麻烦的,没有方法处理】
    Object[] array = new Object[5];
    array[0] = true;
    array[1] = 100;
    array[2] = “Niubility”;
  • 集合的长度是可变的!也可以存放任意类型的数据基本类型的数据使用包装类)!实际开发,集合里面一般也是放相同类型的数据!【它的操作非常方便的,提供了很多便捷的方法】
    ArrayList list = new ArrayList();
    list.add(true);
    list.add(100);
    list.add(“Niubility”);

一、 Collection集合

1、Collection共有属性

1.1单列集合体系结构

在这里插入图片描述

1.2 Collection 常用功能

Collection是所有单列集合的父接口,因此在Collection中定义了单列集合(List和Set)通用的一些方法,这些方法可用于操作所有的单列集合。

public boolean add(E e): // 把给定的对象添加到当前集合中 。【E如果指定了具体类型,那么就只能向集合中添加指定类型的数据,没有指定具体类型,就相当于Object】
public void clear(): // 清空集合中所有的元素。
public boolean remove(E e): // 把给定的对象在当前集合中删除。
public boolean contains(Object obj): // 判断当前集合中是否包含给定的对象。
public boolean isEmpty(): // 判断当前集合是否为空。
public int size(): // 返回集合中元素的个数。
public Object[] toArray(): // 把集合中的元素,存储到数组中

1.3 Iterator迭代器
Iterator接口

在程序开发中,经常需要遍历集合中的所有元素。针对这种需求,JDK专门提供了一个接口java.util.Iterator。

想要遍历Collection集合,那么就要获取该集合对应的迭代器来完成迭代操作,下面介绍一下获取迭代器的方法:

// Iterator接口里面的方法都需要使用对象来调用!所有的单列集合都有iterator()方法(就可以得到Iterator接口的实例对象)
public Iterator iterator(): // 获取集合对应的迭代器,用来遍历集合中的元素的

**迭代:**即Collection集合元素的通用获取方式。在取元素之前先要判断集合中有没有元素,如果有,就把这个元素取出来,继续在判断,如果还有就再取出来,一直把集合中的所有元素全部取出。

Iterator接口的常用方法

public boolean hasNext(): // 如果仍有元素可以迭代,则返回 true。
public E next(): // 返回迭代的下一个元素。

代码演示:

/*
    迭代器Iterator: 获取集合中所有的数据
        在获取数据之前,先判断集合里面是否有数据,有就取出来,然后继续判断继续取,一直到判断集合里面没有数据的时候就不取了。

    使用迭代器:
        1. 通过集合对象获得迭代器对象
        2. 调用迭代器的hasNext()方法判断集合中是否有数据
        3. 只要有数据,那么就调用next()方法获取集合中的数据!
 */
public class Test01 {

    public static void main(String[] args) {

        // 创建集合对象
        Collection coll = new ArrayList(); // 多态
        // 添加数据到集合中去
        coll.add("itheima");
        coll.add("itcast");
        coll.add("javaee");

        // 通过集合对象获得迭代器对象
        Iterator iterator = coll.iterator(); // 将集合的数据封装到迭代器中去了

        // 判断
        while(iterator.hasNext()){
            // 获取下一个数据
            Object obj = iterator.next();
            System.out.println("obj:"+ obj);
        }

    }

}

注意1:在进行集合元素获取时,如果集合中已经没有元素了,还继续使用迭代器的next方法,将会抛出java.util.NoSuchElementException没有集合元素异常

public class Test01 {

    public static void main(String[] args) {

        // 创建集合对象
        Collection coll = new ArrayList(); // 多态
        // 添加数据到集合中去
        coll.add("itheima");
        coll.add("itcast");
        coll.add("javaee");

        // 通过集合对象获得迭代器对象
        Iterator iterator = coll.iterator(); // 将集合的数据封装到迭代器中去了

        // 判断
        while(coll.hasNext()){
            // 获取下一个数据
            Object obj = iterator.next(); 
            System.out.println("obj:"+ obj);
        }
		System.out.println(iterator.next()); // 迭代器中的元素数据已经取完了,还在获取,就会出现这个没有此元素异常!
    }

}

注意2:在进行集合元素获取时,如果添加或移除集合中的元素 , 将无法继续迭代 , 将会抛出ConcurrentModificationException并发修改异常.

public class Test02 {

    public static void main(String[] args) {

        // 创建集合对象
        Collection coll = new ArrayList(); // 多态
        // 添加数据到集合中去
        coll.add("itheima");
        coll.add("itcast");
        coll.add("javaee");

        // 通过集合对象获得迭代器对象
        Iterator iterator = coll.iterator(); // 将集合的数据封装到迭代器中去了

        // 此时集合和迭代器是2个内容(里面的数据是一样的!)
        while(iterator.hasNext()){
            // 获取下一个数据
            Object obj = iterator.next();
            System.out.println("obj:"+ obj);

            // 修改集合的数据(增删改)
            coll.add("完犊子了。。。"); // ConcurrentModificationException:并发修改异常!

        }

    }

}
1595297182251
1.4 迭代器的实现原理
	当遍历集合时,首先通过调用集合的iterator()方法获得迭代器对象,然后使用hashNext()方法判断集合中是否存在下一个元素,如果存在,则调用next()方法将元素取出,否则说明已到达了集合末尾,停止遍历元素。Iterator迭代器对象在遍历集合时,内部采用指针的方式来跟踪集合中的元素。在调用Iterator的next方法之前,迭代器的索引位于第一个元素之前,不指向任何元素,当第一次调用迭代器的next方法后,迭代器的索引会向后移动一位,指向第一个元素并将该元素返回,当再次调用next方法时,迭代器的索引会指向第二个元素并将该元素返回,依此类推,直到hasNext方法返回false,表示到达了集合的末尾,终止对元素的遍历。
1595298056839

迭代器不允许在迭代数据的过程中对集合中的数据进行修改操作,但是之前的普通循环遍历是可以的!

下列说法错误的是:( B )

A: 迭代器是用来迭代集合容器的;
B: 一个迭代器可以对一个集合迭代多次;
C: 迭代器只能从头到尾迭代,不能倒着迭代;
D: 迭代器迭代集合时,不能使用迭代器之外的方法修改集合的长度

1.5 增强for

增强for循环(也称for each循环)是JDK1.5以后出来的一个高级for循环,专门用来遍历数组和集合的。它的内部原理其实是个Iterator迭代器,所以在遍历的过程中,不能对集合中的元素进行增删改操作

* 普通for格式:
        // 在遍历集合的过程中,可以对集合中的元素数据进行修改(增删改)操作!
		for(int i=0;i<list.size();i++){
            // 获得单个对象的数据
            Object obj = list.get(i);
		}
* 增强for格式:
		// 在遍历集合的过程中,不能对集合中的元素数据进行修改(增删改)操作!【底层是迭代器】
		for(数据类型 变量名称:集合对象或者数组){
            
		}	
* 注意:
	① 增强for循环必须有被遍历的目标,目标只能是Collection或者是数组;
	② 增强for(迭代器)仅仅作为遍历操作出现,不能对集合进行增删改元素操作,否则抛出ConcurrentModificationException并发修改异常
public class Test03 {

    public static void main(String[] args) {

        // 创建集合对象
        Collection coll = new ArrayList(); // 多态
        // 添加数据到集合中去
        coll.add("itheima");
        coll.add("itcast");
        coll.add("javaee");

        // 普通遍历
        /*
            for (int i = 0; i < coll.size(); i++) {
                // 需要调用子类独有的方法,向下转型
                ArrayList list = (ArrayList) coll;
                // 得到单个对象
                Object o = list.get(i);
                System.out.println("o:" + o);
                list.remove(o); // 可以的!
            }
        */

        // 增强for循环  【快捷键:被遍历集合对象.iter+回车】
        for (Object obj : coll) { // 【集合在创建的时候没有泛型类型,默认是Object类型,那么遍历集合coll得到的单个对象的数据类型就是Object】
            System.out.println("obj:" + obj);
            // 删除数据
            // coll.remove(obj);  // 并发修改异常ConcurrentModificationException
        }

    }

}
1.6 Collections常用功能

java.utils.Collections是集合工具类,用来对集合进行操作。常用方法如下:

public static void shuffle(List<?> list) : // 打乱集合顺序。
public static void sort(List list) : // 将集合中元素按照默认规则排序。
public static void sort(List list,Comparator<? super T> ) : // 将集合中元素按照指定规则排序。
static boolean addAll(Collection<? super T> c, T… elements): // 将所有指定的元素添加到指定的集合。

1.7Comparator比较器

指定排序的规则的一个接口(java.util包下),重写该接口下的一个方法compare(T o1, T o2)即可!

public class Test02 {

    public static void main(String[] args) {

        // 创建集合对象
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(10);
        list1.add(60);
        list1.add(20);
        list1.add(80);
        list1.add(30);
        System.out.println("list1:" + list1); // list1:[10, 60, 20, 80, 30]

        // 排序(默认排序,自然排序)
        Collections.sort(list1);
        System.out.println("list1:" + list1); // list1:[10, 20, 30, 60, 80]

        // 升序排序!
        Collections.sort(list1, new Comparator<Integer>() {
            // 此方法是排序的核心
            @Override
            public int compare(Integer o1, Integer o2) {
                // 前-后 升序! 后-前 降序!(前后针对的是2个参数o)
                return o1-o2;
            }
        });
        System.out.println("list1:" + list1); // list1:[10, 20, 30, 60, 80]

        // 降序排序!
        Collections.sort(list1, new Comparator<Integer>() {
            // 此方法是排序的核心
            @Override
            public int compare(Integer o1, Integer o2) {
                // 前-后 升序! 后-前 降序!(前后针对的是2个参数o)
                return o2-o1;
            }
        });
        System.out.println("list1:" + list1); // list1:[80, 60, 30, 20, 10]
    }

}
public class Test03 {

    public static void main(String[] args) {

        // 创建集合
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("abc");
        list2.add("bbd");
        list2.add("cbd");
        list2.add("bac");

        System.out.println("list2:"+list2); // list2:[abc, bbd, cbd, bac]
        // 默认排序
        Collections.sort(list2);
        System.out.println("list2:"+list2); // list2:[abc, bac, bbd, cbd]

        // 自己指定规则(升序!)
        Collections.sort(list2, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // 前-后:升序; 后-前:降序!
                return o1.compareTo(o2);
            }
        });
        System.out.println("list2:"+list2); // list2:[abc, bac, bbd, cbd]

        // 降序!
        Collections.sort(list2, new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                // 后-前:降序!
                return  o2.compareTo(o1);
            }
        });
        System.out.println("list2:"+list2); // list2:[abc, bac, bbd, cbd]
    }
}

比较器应用在 List排序(Collections.sort(List list,new Comparator)) 和 TreeSet的构造方法中

1.3 可变参数

在JDK1.5之后,如果我们定义一个方法需要接受多个参数,并且多个参数类型一致,我们可以对其简化

* 格式:
	修饰符 返回值类型 方法名(数据类型... 形参名){  }
/*
    Collections工具类通过了对集合进行便捷操作的静态方法:
        static <T> boolean addAll(Collection<? super T> c, T... elements): //  将所有指定的元素添加到指定的集合。

    T...elements:它是一个可变参数!
        1. 可变参数的类型是集合的泛型类型
        2. 参数可以传递任意个(0个也行)
        3. 方法的参数,里面除了有可变参数,还有额外参数(这些个参数的类型全都一样,那么额外的参数必须放在可变参数的前面)

 */
public class Test04 {

    public static void main(String[] args) {

        // 创建集合对象
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(10);
        list1.add(60);
        list1.add(20);
        list1.add(80);
        list1.add(30);
        System.out.println("list1:" + list1); // list1:[10, 60, 20, 80, 30]

        // 使用工具类的addAll方法向集合中添加数据
        ArrayList<Integer> list2 = new ArrayList<>();
        Collections.addAll(list2, 10, 15, 20, 3, 9);
        //Collections.addAll(list2);  // 正确的!
        System.out.println("list2:" + list2); // list2:[10, 15, 20, 3, 9]

    }


}

需求:定义方法,求N个整数的累加和

/*
    可变参数:
        定义方法,求N个整数的累加和
 */
public class Test05 {

    public static void main(String[] args) {
        // 调用方法
        int sum1 = getSum(1, 2, 3);
        System.out.println("sum1:" + sum1);

        // 再次调用方法
        int sum2 = getSum(3, 6, 2, 10, 9);
        System.out.println("sum2:"+ sum2);

    }

    // 定义方法:求N个整数的累加和
    public static int getSum(int... number) { // 将可变参数可以理解为一个可变数组或者集合
        // 定义求和变量
        int sum = 0;
        if (number.length != 0) {
            // 遍历
            for (int i : number) {
                // 累加求和
                sum += i;
            }
        }
        // 返回
        return sum;
    }

}
* 注意:	
	1.一个方法只能有一个可变参数
	2.如果方法中有多个参数,可变参数要放到最后。
public class Test06 {

    public static void main(String[] args) {
        // 调用方法
        int sum1 = getSum(0, 2, 3); // // 第一个参数为为计数器变量赋默认值!
        System.out.println("sum1:" + sum1);

        // 再次调用方法
        int sum2 = getSum(0, 6, 2, 10, 9); // 第一个参数为为计数器变量赋默认值!
        System.out.println("sum2:"+ sum2);

    }

    // 定义方法:求N个整数的累加和
    public static int getSum(int count,int... number) { // 将可变参数可以理解为一个可变数组或者集合
    //public static int getSum(int... number,int count) { // 可变参数与额外参数的数据类型一致,必须将可变参数放在后面!
        // 定义求和变量
        int sum = 0;
        if (number.length != 0) {
            // 遍历
            for (int i : number) {
                // 累加求和
                sum += i;
                count++;
            }
        }
        System.out.println("当前有"+count+"个数据在相加!");
        // 返回
        return sum;
    }

}

应用场景: Collections

在Collections中也提供了添加一些元素方法:

public static <T> boolean addAll(Collection<T> c, T... elements) : // 往集合中添加一些元
public static void main(String[] args) {

    // 创建集合对象
    ArrayList<Integer> list1 = new ArrayList<>();
    list1.add(10);
    list1.add(60);
    list1.add(20);
    list1.add(80);
    list1.add(30);
    System.out.println("list1:" + list1); // list1:[10, 60, 20, 80, 30]

    // 使用工具类的addAll方法向集合中添加数据
    ArrayList<Integer> list2 = new ArrayList<>();
    Collections.addAll(list2, 10, 15, 20, 3, 9);
    //Collections.addAll(list2);  // 正确的!  // list2:[]
    System.out.println("list2:" + list2); // list2:[10, 15, 20, 3, 9]

}

2、List接口

2.1 List接口介绍

java.util.List接口继承自Collection接口,是单列集合的一个重要分支,习惯性地会将实现了List接口的对象称为List集合。

* 特点:有序、有索引、可重复
	①它是一个元素存取有序的集合。 【向集合中存入数据是什么数据,那么取出来的数据就是之前存入数据的顺序】 abc abc 
	②它是一个带有索引的集合,通过索引就可以精确的操作集合中的元素。
	③集合中可以有重复的元素,通过元素的equals方法,来比较是否为重复的元素。
2.2 List接口中的常用方法

List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法。

public void add(int index, E element): // 将指定的元素,添加到该集合中的指定位置上。
public E get(int index): // 返回集合中指定位置的元素。
public E remove(int index): // 移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element):// 用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

2.3 ArrayList集合

java.util.ArrayList集合数据存储的结构是数组结构。元素增删慢,查找快,由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合之一。

public boolean add(E e); // 直接在集合的末尾添加元素数据e
public void add(int index,E e); // 在集合指定index索引位置添加元素数据e 
public E get(int index); // 获得集合总指定index索引位置的元素数据
public E remove(int index); // 删除集合中指定index索引位置的元素数据
public boolean remove(Object obj); // 删除集合中指定的元素数据obj
public E set(int index,E e); // 将集合index索引位置的元素数据修改为e
public int size();  // 获得集合里面元素数据的个数!
2.4 LinkedList集合

java.util.LinkedList集合数据存储的结构是链表结构(双向链表)。方便元素添加、删除的集合。
在这里插入图片描述

实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。这些方法我们作为了解即可

public void addFirst(E e): //将指定元素插入此列表的开头。
public void addLast(E e): // 将指定元素添加到此列表的结尾。
public E getFirst(): // 返回此列表的第一个元素。
public E getLast(): // 返回此列表的最后一个元素。
public E removeFirst(): // 移除并返回此列表的第一个元素。
public E removeLast(): // 移除并返回此列表的最后一个元素。
public E pop(): // 从此列表所表示的堆栈处弹出一个元素。
public void push(E e): // 将元素推入此列表所表示的堆栈。
public boolean isEmpty()// 如果列表不包含元素,则返回true。

public class Test02LinkedList {

public static void main(String[] args) {

    // 创建对象
    LinkedList<String> ll = new LinkedList<>();
    // 造数据
    ll.add("itcast");
    ll.add("itheima");
    ll.add("java");
    ll.add("java");
    System.out.println("ll: " + ll); // ll:[itcast, itheima, java, java] 【LinkedList具备List接口的特点!】

    // 删除(链表的头部)
    String pop = ll.pop();
    System.out.println("pop:" + pop); // pop:itcast

    // 添加(链表的头部)
    ll.push("jack");
    System.out.println("ll: " + ll); // ll: [jack, itheima, java, java]

    // 是否为空
    System.out.println(ll.isEmpty()); // false

    // 删除尾部
    ll.removeLast();
    System.out.println("ll: " + ll ); // ll: [jack, itheima, java]

    // 删除头部
    ll.removeFirst();
    System.out.println("ll: " + ll ); // ll: [itheima, java]

    // 获得头部
    System.out.println(ll.getFirst()); // itheima

    // 获得尾部
    System.out.println(ll.getLast()); // java

    // 头部添加
    ll.addFirst("jack");
    System.out.println("ll: " + ll ); // ll: [jack, itheima, java]

    // 尾部添加
    ll.addLast("rose");
    System.out.println("ll: " + ll ); // ll: [jack, itheima, java, rose]

3、Map接口

3.1 Map接口介绍

现实生活中,我们常会看到这样的一种集合:IP地址与主机名,身份证号与个人,系统用户名与系统用户对象等,这种一一对应的关系,就叫做映射。Java提供了专门的集合类用来存放这种对象关系的对象,即java.util.Map接口。

我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同,如下图。

在这里插入图片描述

* Collection中的集合,元素是孤立存在的(理解为单身),向集合中存储元素采用一个个元素的方式存储。
* Map中的集合,元素是成对存在的(理解为夫妻)。每个元素由键与值两部分组成,通过键可以找对所对应的值。
* Collection中的集合称为单列集合,Map中的集合称为双列集合。
* 需要注意的是,Map中的集合不能包含重复的键,值可以重复;每个键只能对应一个值。【重复key,其值会被覆盖!】
3.2 Map的常用子类

通过查看Map接口描述,看到Map有多个子类,这里我们主要讲解常用的HashMap集合、LinkedHashMap集合、TreeMap集合。

  • HashMap<K,V>:存储数据采用的哈希表(数组、链表、红黑树)结构,元素的存取顺序不能保证一致。由于要保证键的唯一、不重复,需要重写键的hashCode()方法、equals()方法
  • LinkedHashMap<K,V>:HashMap下有个子类LinkedHashMap,存储数据采用的哈希表结构+链表结构。通过链表结构可以保证元素的存取顺序一致;通过哈希表结构可以保证的键的唯一、不重复,需要重写键的hashCode()方法、equals()方法。
  • TreeMap<K,V>:TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;可以对元素的键进行排序,排序方式有两种:自然排序和比较器排序
3.3 Map的常用方法

Map接口中定义了很多方法,常用的如下:

public V put(K key, V value) : // 把指定的键与指定的值添加到Map集合中。
public V remove(Object key) : // 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
public V get(Object key)// 根据指定的键,在Map集合中获取对应的值。
public Set<K> keySet() :  // 获取Map集合中所有的键,存储到Set集合中。
public Set<Map.Entry<K,V>> entrySet() : // 获取到Map集合中所有的键值对对象的集合(Set集合)。
public boolean containKey(Object key) : // 判断该集合中是否有此键。
/*
    HashMap:
        无序!唯一(key)!
 */
public class Test01Map {

    public static void main(String[] args) {

        // 创建Map集合对象
        Map<String, String> map = new HashMap<>();

        // 向map集合中添加数据
        map.put("username", "jack");
        map.put("password", "jack");
        map.put("sex", "男");
        map.put("age", "38");
        map.put("address", "天津滨海新区互联网教育大厦203");

        // 打印
        System.out.println("map:" + map); // map:{password=123456, address=天津滨海新区互联网教育大厦203, sex=男, age=38, username=jack}

        // 再次添加
        map.put("age", "28");  // 重复的key再次赋值,修改数据!
        System.out.println("map:" + map); // map:{password=123456, address=天津滨海新区互联网教育大厦203, sex=男, age=28, username=jack}

        // 获取
        String address = map.get("address");
        System.out.println("address:" + address); // address:天津滨海新区互联网教育大厦203

        // 删除(返回被删除的那个key对应的值)
        String password = map.remove("password");
        System.out.println("password:" + password); // password:jack
        System.out.println("map:" + map); // map:{address=天津滨海新区互联网教育大厦203, sex=男, age=28, username=jack}

        // 判断map中是否包含指定的key
        System.out.println(map.containsKey("sex")); // true
        System.out.println(map.containsKey("email")); // false

    }

}

注意:指定的键(key)在集合中存在,则返回值为集合中键对应的值(该值为替换前的值),并把指定键所对应的值,替换成指定的新值。

tips:Map接口中的集合都有两个泛型变量<K,V>,在使用时,要为两个泛型变量赋予数据类型。两个泛型变量<K,V>的数据类型可以相同,也可以不同。

// 创建Map集合对象
Map<String, String> map = new HashMap<>();

// 向map集合中添加数据
map.put("username", "jack");
map.put("password", "123456");
map.put("username", "rose"); // 此处会将username的进行修改,用rose替换jack


Map<String, String> map = new HashMap<>(); // key,value的泛型类型相同!
Map<Integer,Character> map = new HashMap<>(); // key,value的泛型类型不同!
3.4 Map的遍历 【重点】
方式1: 键找值方式
/*
    Map的遍历
        方式一:先获得所有的key(构成一个Set集合),然后通过key获得对应的value
            * keySet()方法:获得map中所有的key构成的Set集合
            * 遍历所有的key,然后通过map的getKey(Object obj)方法获得指定key的value值!
 */
public class Test02Map {

    public static void main(String[] args) {

        // 创建Map集合对象
        Map<String, String> map = new HashMap<>();

        // 向map集合中添加数据
        map.put("username", "jack");
        map.put("password", "123456");
        map.put("sex", "男");
        map.put("age", "38");
        map.put("address", "天津滨海新区互联网教育大厦203");

        // 获得map中所有的key
        Set<String> keys = map.keySet();
        for (String key : keys) {
            //System.out.println("key:"+key);
            // 通过key获得value
            String value = map.get(key);
            System.out.println("key="+ key+", value="+value);
        }

    }

}
方式2: 键值对方式
/*
    Map的遍历
        方式二:先获得所有的key(构成一个Set集合),然后通过key获得对应的value
            * 通过map的engtrySet()方法获得map中所有(key,value)键值对(entry实体)构成的Set集合
            * 遍历set集合,获得单个的(key,value)键值对(entry实体)
            * 直接通过getKey获得键(key)的值!通过getValue获得值(value)的值!
 */
public class Test03Map {

    public static void main(String[] args) {

        // 创建Map集合对象
        Map<String, String> map = new HashMap<>();

        // 向map集合中添加数据
        map.put("username", "jack");
        map.put("password", "123456");
        map.put("sex", "男");
        map.put("age","38");
        map.put("address", "天津滨海新区互联网教育大厦203");

        // 通过map的engtrySet()方法获得map中所有(key,value)键值对(entry实体)构成的Set集合
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        // 遍历set集合,获得单个的(key,value)键值对(entry实体)
        for (Map.Entry<String, String> entry : entrySet) {
            // 直接通过getKey获得键(key)的值!通过getValue获得值(value)的值!
            System.out.println("key="+entry.getKey()+", value="+entry.getValue());
        }

    }

}

上面2种方式对应的图解如下:
在这里插入图片描述

注意:Map集合不能直接使用迭代器或者foreach进行遍历。但是转成Set之后就可以使用了。

3.5 HashMap存储自定义类型

练习:每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。

注意:学生姓名相同并且年龄相同视为同一名学生。

public class Student {

    private String name;

    private int age;

    public Student() {

    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void show(){
        System.out.println(this.name + ", " + this.age);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}

/*
    每位学生(姓名,年龄)都有自己的家庭住址。那么,既然有对应关系,则将学生对象和家庭住址存储到map集合中。学生作为键, 家庭住址作为值。

    学生姓名相同并且年龄相同视为同一名学生
 */
public class StudentTest {

    public static void main(String[] args) {
        // 创建Map对象
        Map<Student,String> map = new HashMap<>();

        // 创建对个学生对象
        Student s1 = new Student("jack",38);
        Student s2 = new Student("jack",18);
        Student s3 = new Student("jack",38);  // 姓名相同并且年龄相同视为同一名学生 (map的key一样了!)
        Student s4 = new Student("rose",18);

        // 将多个学生对象作为key, 住址作为value,添加到map集合
        map.put(s1,"北京");
        map.put(s2,"南京");
        map.put(s3,"天津"); // 添加不进去!(s3和s1是重复的!)
        map.put(s4,"东京");

        // 遍历(通过key找值的方式)
        for (Student student : map.keySet()) {
            // 获得key的值!
            student.show();
            // 获得value的值
            String address = map.get(student);
            System.out.println(address);
        }

        // 键值对方式的遍历!
        /*for (Map.Entry<Student, String> entry : map.entrySet()) {

        }*/
    }
}
* 当给HashMap中存放自定义对象时,如果自定义对象作为key存在,这时要保证对象唯一,必须复写对象的hashCode和equals方法(如果忘记,请回顾HashSet存放自定义对象)。
* 如果要保证map中存放的key和取出的顺序一致,可以使用java.util.LinkedHashMap集合来存放。
3.6 LinkedHashMap介绍

在HashMap下面有一个子类LinkedHashMap,它是链表和哈希表(数组+链表+红黑树)组合的一个数据存储结构。

/*
    HashMap:无序!
	LinkedHashMap:有序!
 */
public class Test01 {

    public static void main(String[] args) {
        // 创建HashMap集合对象
        Map<String, String> map = new HashMap<>();

        // 向map集合中添加数据
        map.put("username", "jack");
        map.put("password", "123456");
        map.put("sex", "男");
        map.put("age", "38");
        map.put("address", "天津滨海新区互联网教育大厦203");

        // 打印【无序!】
        System.out.println("map:" + map); // map:{password=123456, address=天津滨海新区互联网教育大厦203, sex=男, age=38, username=jack}

        ///

        // 创建LinkedHashMap
        Map<String, String> map1 = new LinkedHashMap<>();

        // 向map集合中添加数据
        map1.put("username", "jack");
        map1.put("password", "123456");
        map1.put("sex", "男");
        map1.put("age", "38");
        map1.put("address", "天津滨海新区互联网教育大厦203");

        // 打印【无序!】
        System.out.println("map1:" + map1); // map1:{username=jack, password=123456, sex=男, age=38, address=天津滨海新区互联网教育大厦203}
    }

}
3.7 TreeMap集合

TreeMap集合和Map相比没有特有的功能,底层的数据结构是红黑树;可以对元素的键进行排序,排序方式有两种:自然排序和比较器排序;到时使用的是哪种排序,取决于我们在创建对象的时候所使用的构造方法;

public TreeMap() // 使用自然排序
public TreeMap(Comparator<? super K> comparator) // 比较器排

自然排序:

/*
    HashMap: 无序!唯一(key)!
    LinkedHashMap: 有序!唯一(key)!
    TreeMap: 可排序(针对key)!唯一(唯一)!
 */
public class StudentDemo {

    public static void main(String[] args) {

        // LinkedHashMap
        Map<String,Student> map1 = new LinkedHashMap<>();
        Student s1 = new Student("jack",38);
        Student s2 = new Student("rose",18);
        Student s3 = new Student("rose",18);
        Student s4 = new Student("jack",18);
        map1.put("bbc",s1);
        map1.put("bac",s2);
        map1.put("cbd",s3);
        map1.put("cba",s4);
        // 遍历
        for (String s : map1.keySet()) {
            System.out.println(s); // 存的是什么顺序,取的就是什么顺序!(bbc bac cbd cba)
        }
        System.out.println("======================================");
        //

        // TreeMap(会排序的!默认升序!)
        Map<String,Student> map2 = new TreeMap<>();
        map2.put("bbc",s1);
        map2.put("bac",s2);
        map2.put("cbd",s3);
        map2.put("cba",s4);
        // 遍历
        for (String s : map2.keySet()) {
            System.out.println(s); // 存的是什么顺序,取的就是什么顺序!(bac bbc cba cbd)
        }
        System.out.println("=======================================");

    }

}

比较器排序:

/*
    HashMap: 无序!唯一(key)!
    LinkedHashMap: 有序!唯一(key)!
    TreeMap: 可排序(针对key)!唯一(唯一)!
 */
public class StudentDemo {

    public static void main(String[] args) {

        // LinkedHashMap
        Map<String,Student> map1 = new LinkedHashMap<>();
        Student s1 = new Student("jack",38);
        Student s2 = new Student("rose",18);
        Student s3 = new Student("rose",18);
        Student s4 = new Student("jack",18);
        map1.put("bbc",s1);
        map1.put("bac",s2);
        map1.put("cbd",s3);
        map1.put("cba",s4);
        // 遍历
        for (String s : map1.keySet()) {
            System.out.println(s); // 存的是什么顺序,取的就是什么顺序!(bbc bac cbd cba)
        }
        System.out.println("======================================");
        //

        // TreeMap(会排序的!降序!)
        Map<String,Student> map3 = new TreeMap<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                return o2.charAt(0)-o1.charAt(0);
            }
        });
        map3.put("abc",s1);
        map3.put("bac",s2);
        map3.put("cbd",s3);
        map3.put("dba",s4);
        // 遍历
        for (String s : map3.keySet()) {
            System.out.println(s); // 存的是什么顺序,取的就是什么顺序!(dba cbd bac abc)
        }

    }

}
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值