JavaSE 集合进阶

JavaSE 集合进阶

  • 1. Collection
    • 1.1 集合知识回顾
    • 1.2 集合类体系结构
    • 1.3 Collection 集合概述和使用
    • 1.4 Collection 集合常用方法
    • 1.5 Collection 集合的遍历
    • 1.6 案例
  • 2. List
    • 2.1 List 集合概述和特点
    • 2.2 List 集合特有的方法
    • 2.3 并发修改异常
    • 2.4 ListIterator
    • 2.5 增强 for 循环
    • 2.6 数据结构
    • 2.7 常见数据结构之栈
    • 2.8 常见数据结构之队列
    • 2.9 常见数据结构之数组
    • 2.10 常见数据结构之链表
    • 2.11 List 集合子类特点
    • 2.12 LinkedList 集合的特有功能
  • 3. Set
    • 3.1 Set 集合的概述和特点
    • 3.2 哈希值
    • 3.3 HashSet 集合概述和特点
    • 3.4 HashSet 集合保证元素唯一性源码分析
    • 3.5 常见数据结构之哈希表
    • 3.6 LinkedHashSet 集合概述和特点
    • 3.7 TreeSet 集合概述和特点
    • 3.8 自然排序 Comparable 的使用
    • 3.9 比较器排序 Comparator 的使用
  • 4. 泛型
    • 4.1 泛型概述
    • 4.2 泛型类
    • 4.3 泛型方法
    • 4.4 泛型接口
    • 4.5 类型通配符
    • 4.6 可变参数
    • 4.7 可变参数的使用
  • 5. Map
    • 5.1 Map 集合概述和使用
    • 5.2 Map 集合的基本功能
    • 5.3 Map集合的获取功能
    • 5.4 Map 集合的遍历(方式1)
    • 5.5 Map 集合的遍历(方式2)
  • 6. Collections
    • 6.1 Collections 概述和使用
    • 6.2 模拟斗地主
    • 6.3 模拟斗地主(升级版)

1. Collection

1.1 集合知识回顾

集合类的特点:
提供一种存储空间可变的存储模型,存储的数据容量可以随时发生改变

1.2 集合类体系结构

JavaSE 集合进阶_第1张图片

1.3 Collection 集合概述和使用

Collection 集合概述:

  • 是单列集合的顶层接口,它表示一组对象,这些对象也被称为Collection 的元素
  • JDK 不提供此接口的任何直接实现,它提供更具体的子接口(如Set和List)实现

创建Collection 集合的对象

  • 多态的方式
  • 具体的实现类ArrayList
package com.Collection;

import java.util.ArrayList;
import java.util.Collection;

public class Demo01 {
     
    public static void main(String[] args){
     
        //创建Collection集合对象
        Collection<String> c = new ArrayList<String>();
        //添加元素:boolean add(E e)
        c.add("cappuccino");
        c.add("love");
        c.add("bug");
        System.out.println(c);
    }
}

JavaSE 集合进阶_第2张图片

1.4 Collection 集合常用方法

JavaSE 集合进阶_第3张图片

1.5 Collection 集合的遍历

Iterator:迭代器,集合的专用遍历方式

  • Iterator iterator():返回次集合中元素的迭代器,通过集合的iterator()方法得到
  • 迭代器是通过集合的iterator()方法得到的,所以我们说它是依赖于集合而存在的

Iterator中的常用方法:

  • E next():返回迭代中的下一个元素
  • boolean hasNext():如果迭代具有更多元素,则返回true
package com.Collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

public class Demo02 {
     
    public static void main(String[] args){
     
        //创建Collection集合对象
        Collection<String> c = new ArrayList<String>();
        //添加元素:boolean add(E e)
        c.add("cappuccino");
        c.add("love");
        c.add("bug");
        /*
        Iterator  iterator():返回次集合中元素的迭代器,
        通过集合的iterator()方法得到
         */
        Iterator<String> it = c.iterator();
        /*boolean hasNext():如果迭代具有更多元素,则返回true
          E next():返回迭代中的下一个元素
         */
        while(it.hasNext()){
     
            String s = it.next();
            System.out.println(s);
        }
    }
}

JavaSE 集合进阶_第4张图片

1.6 案例

  • 需求:
    创建一个存储学生对象的集合,存储三个学生对象,使用程序实现在控制台遍历该集合

  • 思路:

    1. 定义学生类
    2. 创建Collection集合对象
    3. 创建学生对象
    4. 把学生添加到集合
    5. 遍历集合(迭代器方式)
package com.Collection;

public class Student {
     
    private String name;
    private int age;
    public Student(){
     }
    public Student(String name, int age) {
     
        this.name = name;
        this.age = age;
    }
    public String getName() {
     
        return name;
    }

    public void setName(String name) {
     
        this.name = name;
    }

    public int getAge() {
     
        return age;
    }

    public void setAge(int age) {
     
        this.age = age;
    }
}
package com.Collection;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/*
  需求:
    创建一个存储学生对象的集合,存储三个学生对象,使用程序实现在控制台遍历该集合
  思路:
    1.定义学生类
    2.创建Collection集合对象
    3.创建学生对象
    4.把学生添加到集合
    5.遍历集合(迭代器方式)
 */
public class CollectionTest {
     
    public static void main(String[] args){
     
        //创建Collection集合对象
        Collection<Student> c = new ArrayList<Student>();
        //创建学生对象
        Student s1 = new Student("苦瓜",21);
        Student s2 = new Student("半仙儿",22);
        Student s3 = new Student("研",23);
        //把学生添加到集合
        c.add(s1);
        c.add(s2);
        c.add(s3);
        //遍历集合(迭代器方式)
        Iterator<Student> it = c.iterator();
        while(it.hasNext()){
     
            Student s = it.next();
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

JavaSE 集合进阶_第5张图片

2. List

2.1 List 集合概述和特点

  • List 集合概述

    1. 有序集合(也成为了序列),用户可以精确控制列表中每个元素的插入位置。用户可以通过整数索引访问元素,并搜索列表中的元素
    2. 与 set 集合不同,列表通常允许重复的元素
  • List 集合的特点

    1. 有序:存储和取出元素顺序一致
    2. 可重复:存储的元素可以重复
package com.List;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
    List 集合的特点:
        有序:存储和取出元素顺序一致
        可重复:存储的元素可以重复
 */
public class Demo01 {
     
    public static void main(String[] args){
     
        //创建集合对象
        List<String> list = new ArrayList<String>();
        //添加元素
        list.add("研");
        list.add("半仙儿");
        list.add("苦瓜");
        list.add("研");
        //输出集合
        System.out.println(list);

        //采用迭代器的方式遍历
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
     
            String s = it.next();
            System.out.println(s);
        }
    }
}

JavaSE 集合进阶_第6张图片

2.2 List 集合特有的方法

JavaSE 集合进阶_第7张图片

2.3 并发修改异常

  • 并发修改异常:ConcurrentModificationException
  • 产生原因:
    迭代器遍历的过程中,通过集合对象修改了集合中元素的长度,造成了迭代器获取元素中预期修改值和实际修改值不一致
  • 解决方案:
    用for循环遍历,然后用集合对象做相应的操作即可
package com.List;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
    需求:
        集合里面有三个元素,遍历集合,得到每一个元素,看有没有"研"这个元素;
        如果有,就添加一个"粉色匡威"元素
    ConcurrentModificationException:并发修改异常
    当不允许这样的修改时,可以通过检测到对象的并发修改的方法来抛出此异常
 */

public class ConcurrentModificationException {
     
    public static void main(String[] args){
     
        List<String> list = new ArrayList<String>();
        list.add("苦瓜");
        list.add("半仙儿");
        list.add("研");
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
     
            String s = it.next();
            if(s.equals("研")){
     
                list.add("粉色匡威");
            }
        }
//        for(int i=0;i
//            String s = list.get(i);
//            if(s.equals("研")){
     
//                list.add("粉色匡威");
//            }
//        }
        System.out.println(list);
    }
}

JavaSE 集合进阶_第8张图片

/*
	并发修改异常的源码分析
*/
public interface List<E>{
     
    Iterator<E> iterator();
    boolean add(E e);
}

public abstract class AbstractList<E>{
     
    protected int modCount = 0;
}

public class ArrayList<E> extends AbstractList<E> implements List<E>{
     

        public E get(int index) {
     
            rangeCheck(index);
            return elementData(index);
        }

        public boolean add(E e) {
     
            ensureCapacityInternal(size + 1);  /* Increments modCount!!
                                                  modCount++
                                               */
            elementData[size++] = e;
            return true;
        }

        public Iterator<E> iterator() {
     
           return new Itr();
        }

        private class Itr implements Iterator<E> {
     
            int expectedModCount = modCount;

            /*
                modCount:实际修改集合的次数
                expectedModCount:预期修改集合的次数
            */


            public E next() {
     
                checkForComodification();
                int i = cursor;
                if (i >= size)
                    throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length)
                    throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
            }

            final void checkForComodification() {
     
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }
}

2.4 ListIterator

ListIterator: 列表迭代器

  • 通过List集合的 ListIterator() 方法获得,所以说它是List集合特有的迭代器
  • 允许程序员沿任意方向遍历列表的列表迭代器,在迭代期间修改列表,并获取列表中迭代器的当前位置

ListIterator中常用方法:

  • E next():返回迭代中的下一个元素
  • boolean hasNext():如果迭代具有更多元素,则返回 true
  • E previous():返回列表中的上一个元素
  • boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回 true
  • void add(E e):将指定的元素插入列表
package com.ListIterator;

import java.util.ArrayList;
import java.util.List;
import java.util.ListIterator;
/*
    ListIterator: 列表迭代器
        通过List集合的 listIterator() 方法获得,所以说它是List集合特有的迭代器
        允许程序员沿任意方向遍历列表的列表迭代器,在迭代期间修改列表,
        并获取列表中迭代器的当前位置
    ListIterator中常用方法:
        E next():返回迭代中的下一个元素
        boolean hasNext():如果迭代具有更多元素,则返回 true
        E previous():返回列表中的上一个元素
        boolean hasPrevious():如果此列表迭代器在相反方向遍历列表时具有更多元素,则返回 true
        void add(E e):将指定的元素插入列表
 */
public class Demo01 {
     
    public static void main(String[] args){
     
        //创建集合对象
        List<String> list = new ArrayList<String>();
        //添加元素
        list.add("苦瓜");
        list.add("粉色");
        list.add("匡威");
        //通过List集合的 listIterator() 方法获得
//        ListIterator lit = list.listIterator();
//        while(lit.hasNext()){
     
//            String s = lit.next();
//            System.out.println(s);
//        }
//        System.out.println("--------");
//        //逆向遍历(很少用)
//        while(lit.hasPrevious()){
     
//            String s = lit.previous();
//            System.out.println(s);
//        }
        ListIterator<String> lit = list.listIterator();
        while(lit.hasNext()){
     
            String s = lit.next();
            if(s.equals("苦瓜")){
     
                lit.add("研");
            }
        }
        System.out.println(list);
    }
}

JavaSE 集合进阶_第9张图片

/*
	ListIterator源码分析
*/
public interface List<E>{
     
    Iterator<E> iterator();
    ListIterator<E> listIterator();
}

public abstract class AbstractList<E>{
     
    protected int modCount = 0;
}

public class ArrayList<E> extends AbstractList<E> implements List<E>{
     


        public Iterator<E> iterator() {
     
           return new Itr();
        }

        private class Itr implements Iterator<E> {
     
            ...
        }
        public ListIterator<E> listIterator() {
     
            return new ListItr(0);
        }

        private class ListItr extends Itr implements ListIterator<E> {
     

            public void add(E e) {
     
                checkForComodification();

                try {
     
                    int i = cursor;
                    ArrayList.this.add(i, e);
                    cursor = i + 1;
                    lastRet = -1;
                    expectedModCount = modCount;  //重点
                                        /*
                                            列表迭代器的add()方法在添加元素
                                            之后会将实际修改次数赋值给预期修
                                            改次数,所有不会出现并发修改异常
                                        */
                } catch (IndexOutOfBoundsException ex) {
     
                    throw new ConcurrentModificationException();
                }
            }
        }
}

2.5 增强 for 循环

增强for循环:简化数组和 Collection 集合的遍历

  • 实现 Iterable 接口的类允许其对象成为增强型 for 语句的目标
  • 它是 JDK5 之后出现的,其内部原理是一个 Iterator 迭代器

增强 for 的格式

  • 格式:
    for(元素数据类型 变量名:数组或者Collection集合){
    //在此处使用变量即可,该变量就是数组或者集合的元素
    }
  • 范例:
int[] arr = {
     1,2,3};
for(int i:arr){
     
	System.out.println(i);
}
package com.ListIterator;

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

/*
    增强for循环:简化数组和 Collection 集合的遍历
        实现 Iterable 接口的类允许其对象成为增强型 for 语句的目标
        它是 JDK5 之后出现的,其内部原理是一个 Iterator 迭代器

    格式:
        for(元素数据类型 变量名:数组或者Collection集合){
        //在此处使用变量即可,该变量就是数组或者集合的元素
        }
 */
public class ForDemo {
     
    public static void main(String[] args){
     
        int[] arr = {
     1,2,3,4,5,6,7};
        for(int i : arr){
     
            System.out.println(i);
        }
        System.out.println("-------");
        String[] strArray = {
     "苦瓜","半仙儿","研"};
        for(String s : strArray){
     
            System.out.println(s);
        }
        System.out.println("-------");
        List<String> list = new ArrayList<String>();
        list.add("bug");
        list.add("cappuccino");
        list.add("NJUST");
        for(String s : list){
     
            System.out.println(s);
        }
    }
}

  • 案例(学生类省略)
    需求:
    创建一个存储学生对象的集合,存储三个学生对象,使用程序实现在控制台遍历该集合
package com.ListIterator;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/*
  需求:
    创建一个存储学生对象的集合,存储三个学生对象,使用程序实现在控制台遍历该集合
  思路:
    1.定义学生类
    2.创建Collection集合对象
    3.创建学生对象
    4.把学生添加到集合
    5.遍历集合
        5.1 迭代器:集合特有的遍历方式
        5.2 普通for:带有索引的遍历方式
        5.3 增强for:最方便的遍历方式
 */
public class ListDemo {
    public static void main(String[] args){
        //创建集合对象
        List list = new ArrayList();
        //创建学生对象
        Student s1 = new Student("苦瓜",21);
        Student s2 = new Student("半仙儿",22);
        Student s3 = new Student("研",23);
        //把学生添加到集合
        list.add(s1);
        list.add(s2);
        list.add(s3);

        //迭代器:集合特有的遍历方式
        Iterator it = list.iterator();
        while(it.hasNext()){
            Student s = it.next();
            System.out.println(s.getName() + "," + s.getAge());
        }
        System.out.println("-------");
        //普通for:带有索引的遍历方式
        for(int i=0;i

2.6 数据结构

数据结构是计算机存储、组织数据的方式,是指相互之间存在一种或多种特定关系的数据元素的集合。
通常情况下,精心选择的 数据结构可以带来更高的运行或存储效率

2.7 常见数据结构之栈

  • 模型
    JavaSE 集合进阶_第10张图片
  • 栈是一种数据 先进后出 的模型
  • 进栈:A -> B -> C -> D
  • 出栈:D -> C -> B -> A

2.8 常见数据结构之队列

  • 模型
    JavaSE 集合进阶_第11张图片
  • 队列是一种数据 先进先出 的模型
  • 入队列:数据从 后端 进入队列模型的过程
    A -> B -> C -> D
  • 出队列:数据从 前端 离开队列模型的过程
    A -> B -> C -> D

2.9 常见数据结构之数组

  • 模型
    JavaSE 集合进阶_第12张图片
  • 数组是一种 查询快,增删慢 的模型
  • 查询数据通过索引定位,查询任意数据耗时相同,查询速度快
  • 删除数据时,要将原始数据删除,同时后面每个数据前移,删除效率低
  • 添加数据时,添加数据后的每个数据后移,再添加元素,添加效率极低

2.10 常见数据结构之链表

  • 模型
    JavaSE 集合进阶_第13张图片
  • 头结点
    JavaSE 集合进阶_第14张图片
  • 链表的组成
    JavaSE 集合进阶_第15张图片
  • 添加:在数据 AC 之间添加一个数据 B ,保存在地址 54 位置
    1. 数据 B 对应的下一个数据地址指向数据 C
    2. 数据 A 对应的下一个数据地址指向数据 B
      JavaSE 集合进阶_第16张图片
  • 删除数据 BD 之间的数据 C
    1. 数据 B 对应的下一个数据地址指向数据 D
    2. 删除数据 C
      JavaSE 集合进阶_第17张图片
  • 查询数据 D 是否存在,必须从头(head)开始查询
  • 链表是一种 增删快,查询慢 的模型(对比数组)

2.11 List 集合子类特点

  • List 常用子类:ArrayList 和 LinkedList

  • ArrayList:底层数据结构是数组,查询快,增删慢

  • LinkedList:底层数据结构是链表,增删快,查询慢

  • 练习:
    分别使用 ArrayList 和 LinkedList 完成存储字符串并遍历

package com.List;

/*
    List 常用子类:
    ArrayList 和 LinkedList
    ArrayList:底层数据结构是数组,查询快,增删慢
    LinkedList:底层数据结构是链表,增删快,查询慢
    练习:
    分别使用 ArrayList 和 LinkedList 完成存储字符串并遍历
 */

import java.util.ArrayList;
import java.util.LinkedList;

public class ListDemo {
     
    public static void main(String[] args){
     
        ArrayList<String> array = new ArrayList<String>();
        array.add("苦瓜");
        array.add("半仙儿");
        array.add("NJUST");
        for(String s : array){
     
            System.out.println(s);
        }
        System.out.println("-------");
        LinkedList<String> linked = new LinkedList<String>();
        linked.add("FH");
        linked.add("HNIST");
        linked.add("NJUST");
        for(String s : linked){
     
            System.out.println(s);
        }
    }
}

2.12 LinkedList 集合的特有功能

JavaSE 集合进阶_第18张图片

package com.List;

/*
    LinkedList集合的特有功能:
        public void addFirst(E e):在该列表开头插入指定元素
        public void addLast(E e):将指定的元素追加到此列表的末尾
        public E getFirst():返回此列表中的第一个元素
        public E getLast():返回此列表中的最后一个元素
        public E removeFirst():从此列表中删除并返回第一个元素
        public E removeLast():从此列表中删除并返回最后一个元素
 */

import java.util.LinkedList;

public class LinkedListDemo {
     
    public static void main(String[] args){
     
        LinkedList<String> linked = new LinkedList<String>();
        linked.add("HNIST");
        linked.add("FH");
        linked.add("NJUST");

//        linked.addFirst("bug");
//        linked.addLast("bug");
//        System.out.println(linked.getFirst());
//        System.out.println(linked.getLast());
//        System.out.println(linked.removeFirst());
//        System.out.println(linked.removeLast());

        System.out.println(linked);
    }
}

3. Set

3.1 Set 集合的概述和特点

  • set 集合的特点:

    1. 不包含重复元素的集合
    2. 没有带索引的方法,所以不能使用普通 for 循环遍历
  • 案例

package com.set;

import java.util.HashSet;
import java.util.Set;

/*
    set 集合的特点:
        1.不包含重复元素的集合
        2.没有带索引的方法,所以不能使用普通 for 循环遍历
    HashSet:对集合的迭代顺序不作任何保证
 */

public class Demo01 {
     
    public static void main(String[] args){
     
        //创建集合对象
        Set<String> set = new HashSet<String>();
        //添加元素
        set.add("苦瓜");
        set.add("半仙儿");
        set.add("粉色匡威");
        //不包含重复元素
        set.add("粉色匡威");//只输出一个"粉色匡威"
        //遍历
        for(String s : set){
     
            System.out.println(s);
        }
    }
}

3.2 哈希值

  • 哈希值:哈希值是 JDK 根据对象的 地址 或者 字符串 或者 数字 算出来的 int 类型的 数值

  • Object 类中有一个方法可以 获取对象的哈希值

    • public int hashCode():返回对象的哈希码值
  • 对象的哈希值特点:

    1. 同一个对象多次调用hashCode()方法返回的哈希值相同
    2. 默认情况下,不同对象的哈希值是不同的,通过方法重写(重写hashCode()方法),可以实现不同对象的哈希值是相同的
package com.set;

public class Student {
     
    private String name;
    private int age;

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

    public String getName() {
     
        return name;
    }

    public void setName(String name) {
     
        this.name = name;
    }

    public int getAge() {
     
        return age;
    }

    public void setAge(int age) {
     
        this.age = age;
    }
    //重写hashCode()方法
//    public int hashCode(){
     
//        return 367;
//    }

}

package com.set;
/*
    哈希值:
        哈希值是 JDK 根据对象的 地址 或者 字符串 或者 数字 算出来的 int 类型的 数值
    Object 类中有一个方法可以 获取对象的哈希值
        public int hashCode():返回对象的哈希码值
 */
public class HashDemo {
     
    public static void main(String[] args){
     
        //创建学生对象
        Student s1 = new Student("苦瓜",21);
        Student s2 = new Student("苦瓜",21);
        //同一个对象多次调用hashCode()方法返回的哈希值相同
        System.out.println(s1.hashCode());//325040804
        System.out.println(s1.hashCode());//325040804
        System.out.println("-------");
        //默认情况下,不同对象的哈希值是不同的
        //通过方法重写(重写hashCode()方法),可以实现不同对象的哈希值是相同的
        System.out.println(s2.hashCode());//1173230247
        System.out.println("-------");

        System.out.println("hnist".hashCode());//99427780
        System.out.println("njust".hashCode());//104861274
        System.out.println("-------");

        /*
            字符串重写了hashCode()
            这两个字符串根据重写的方法得出的hash值超出了int的范围
            不能保证准确,所以是一样的
         */
        System.out.println("重地".hashCode());//1179395
        System.out.println("通话".hashCode());//1179395

        System.out.println("Aa".hashCode());//2112
        System.out.println("BB".hashCode());//2112

        System.out.println("苦瓜".hashCode());//1068726





    }
}

3.3 HashSet 集合概述和特点

  • HashSet 集合特点:

    1. 底层数据结构是哈希表
    2. 对集合的迭代顺序不做任何保证,也就是说不保证存储和取出的元素顺序一致
    3. 没有带索引的方法,所以不能使用普通 for 循环遍历(用迭代器或增强 for)
    4. 由于是 set 集合,所以是不包含重复元素的集合
  • 案例

package com.set;

import java.util.HashSet;

/*
    hashSet 集合特点:
        1. 底层数据结构是哈希表
        2. 对集合的迭代顺序不做任何保证,也就是说不保证存储和取出的元素顺序一致
        3. 没有带索引的方法,所以不能使用普通 for 循环遍历(用迭代器或增强 for)
        4. 由于是 set 集合,所以是不包含重复元素的集合
 */
public class HashSetDemo {
     
    public static void main(String[] args){
     
        //创建集合对象
        HashSet<String> hs = new HashSet<String>();
        hs.add("苦瓜");
        hs.add("半仙儿");
        hs.add("njust");
        hs.add("njust");

        for(String s : hs){
     
            System.out.println(s);
        }
    }
}

3.4 HashSet 集合保证元素唯一性源码分析

HashSet 集合添加一个元素的过程:
JavaSE 集合进阶_第19张图片

/*
	HashSet 集合保证元素唯一性的源码分析
 */

//创建集合对象
HashSet<String> hs = new HashSet<String>();

//添加元素
hs.add("苦瓜");
hs.add("半仙儿");
hs.add("njust");

-------------------------

public boolean add(E e) {
     
    return map.put(e, PRESENT)==null;
}

static final int hash(Object key) {
     
    int h;
    return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

public V put(K key, V value) {
     
    return putVal(hash(key), key, value, false, true);
}

//这个hash值是元素调用hashCode()方法获得的
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
     
    Node<K,V>[] tab; Node<K,V> p; int n, i;

    //如果hash表没有初始化,就对其进行初始化
    if ((tab = table) == null || (n = tab.length) == 0)
        n = (tab = resize()).length;

    //根据对象的哈希值计算对象的存储位置,如果该位置没有元素,就存储元素
    if ((p = tab[i = (n - 1) & hash]) == null)
        tab[i] = newNode(hash, key, value, null);
    else {
      //如果该位置有元素
        Node<K,V> e; K k;
        /*
            首先比较哈希值:存入的元素和该位置的元素比较哈希值
                如果哈希值不同,会继续向下执行,把元素添加到集合
                如果哈希值相同,会调用对象的equals()方法进行比较
                    如果返回false,会继续向下执行,把元素添加到集合
                    如果返回true,说明元素重复,不存储
         */
        if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
     
            for (int binCount = 0; ; ++binCount) {
     
                if ((e = p.next) == null) {
     
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);
                    break;
                }
                if (e.hash == hash &&
                    ((k = e.key) == key || (key != null && key.equals(k))))
                    break;
                p = e;
            }
        }
        if (e != null) {
      // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();
    afterNodeInsertion(evict);
    return null;
}

  • HashSet 集合存储元素
    要保证元素唯一性,需要重写 hashCode()equals()

3.5 常见数据结构之哈希表

哈希表:

  • JDK8之前,底层采用 数组+链表 实现,可以说是一个元素为链表的数组
  • JDK8以后,在长度比较长的时候,底层实现了优化(暂时不讲)

JavaSE 集合进阶_第20张图片

  • 案例
package com.set.HashSet;

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

    public String getName() {
     
        return name;
    }

    public void setName(String name) {
     
        this.name = name;
    }

    public int getAge() {
     
        return age;
    }

    public void setAge(int age) {
     
        this.age = age;
    }

    //要保证元素唯一性,需要重写 hashCode() 和 equals()

    @Override
    public boolean equals(Object o) {
     
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Student student = (Student) o;

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

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


package com.set.HashSet;

import java.util.HashSet;

/*
    需求:
        创建一个存储学生对象的集合,存储三个学生对象,使用程序实现在控制台遍历该集合
    要求:
        学生对象的成员变量值相同,就认为是同一个对象
    思路;
        1.定义学生类
        2.创建集合对象
        3.创建学生对象
        4.把学生添加到集合
        5.遍历集合(增强for)
        6.在学生类中重写hashCode()和equals()方法(Alt+Ins 自动生成)
 */
public class HashSetDemo {
     
    public static void main(String[] args){
     
        HashSet<Student> hs = new HashSet<Student>();
        Student s1 = new Student("苦瓜",21);
        Student s2 = new Student("半仙儿",22);
        Student s3 = new Student("卡布奇诺",18);
        Student s4 = new Student("半仙儿",22);
        hs.add(s1);
        hs.add(s2);
        hs.add(s3);
        hs.add(s4);

        for(Student s : hs){
     
            System.out.println(s.getName() + "," + s.getAge());
        }

    }
}


3.6 LinkedHashSet 集合概述和特点

  • LinkedHashSet 集合特点:
    1. 它是由哈希表和链表实现的 Set 接口,具有可预测的迭代次序
    2. 由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
    3. 有哈希表保证元素唯一,也就是说没有重复的元素
  • LinkedHashSet 集合练习
package com.set.HashSet;

import java.util.LinkedHashSet;
/*
    LinkedHashSet 集合特点:
        1.它是由哈希表和链表实现的 Set 接口,具有可预测的迭代次序
        2.由链表保证元素有序,也就是说元素的存储和取出顺序是一致的
        3.有哈希表保证元素唯一,也就是说没有重复的元素

 */
public class LinkedHashSetDemo {
     
    public static void main(String[] args){
     
        LinkedHashSet<String> linkedHashSet = new LinkedHashSet<String>();
        linkedHashSet.add("苦瓜");
        linkedHashSet.add("半仙儿");
        linkedHashSet.add("粉色匡威");
        linkedHashSet.add("苦瓜");
        for(String s : linkedHashSet){
     
            System.out.println(s);
        }
    }
}

3.7 TreeSet 集合概述和特点

  • TreeSet 集合特点:

    1. 元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
      TreeSet():根据其元素的自然排序进行排序
      TreeSet(Comparator comparator): 根据指定的比较器进行排序
    2. 没有带索引的方法,所以不能使用普通for循环遍历
    3. 由于是Set集合,所以不包含重复的元素
  • TreeSet 集合练习:存储整数并遍历

package com.set.TreeSet;

import java.util.TreeSet;

/*
    TreeSet 集合特点:
        1.元素有序,这里的顺序不是指存储和取出的顺序,而是按照一定的规则进行排序,具体排序方式取决于构造方法
            TreeSet():根据其元素的自然排序进行排序
            TreeSet(Comparator comparator): 根据指定的比较器进行排序
        2.没有带索引的方法,所以不能使用普通for循环遍历
        3.由于是Set集合,所以不包含重复的元素
 */
public class TreeSetDemo01 {
     
    public static void main(String[] args){
     
        //集合里面存储的只能是引用类型,所以存储整数只能用int的包装类类型Integer
        TreeSet<Integer> ts = new TreeSet<Integer>();
        ts.add(367);
        ts.add(70);
        ts.add(120);
        for(Integer i : ts){
     
            System.out.println(i);
        }
    }
}

JavaSE 集合进阶_第21张图片

3.8 自然排序 Comparable 的使用

  • 需求:
    1. 存储学生对象并遍历,创建TreeSet集合使用 无参构造方法
    2. 按年龄从小到大排序,年龄相同时,按姓名的字母顺序排序
/*
	学生类
 */
package com.set.TreeSet;

public class Student implements Comparable<Student>{
     
    private String name;
    private int age;
    public Student(){
     }
    public Student(String name, int age) {
     
        this.name = name;
        this.age = age;
    }

    public String getName() {
     
        return name;
    }

    public void setName(String name) {
     
        this.name = name;
    }

    public int getAge() {
     
        return age;
    }

    public void setAge(int age) {
     
        this.age = age;
    }

    @Override
    public int compareTo(Student s) {
     
//        return 0;   //重复元素,不添加
//        return 1;   //升序
//        return -1;  //降序
        //按年龄从小到大排序
        int num1 = this.age - s.age;   //升序
//        int num = s.age - this.age; // 降序
        //年龄相同时,按姓名的字母顺序排序
        int num2 = num1==0?this.name.compareTo(s.name):num1;
        return num2;
    }
}

package com.set.TreeSet;

import sun.reflect.generics.tree.Tree;

import java.util.TreeSet;

/*
    需求:
        1.存储学生对象并遍历,创建TreeSet集合使用无参构造方法
        2.按年龄从小到大排序,年龄相同时,按姓名的字母顺序排序
 */
public class TreeSetDemo02 {
     
    public static void main(String[] args) {
     
        TreeSet<Student> ts = new TreeSet<Student>();
        Student s1 = new Student("苦瓜", 21);
        Student s2 = new Student("半仙儿", 22);
        Student s3 = new Student("守约", 18);
        Student s4 = new Student("卡布奇诺",18);
        Student s5 = new Student("卡布奇诺",18);
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        for (Student s : ts) {
     
            System.out.println(s.getName() + "," + s.getAge());
        }
    }
}

  • 结论
    1. 用TreeSet集合存储自定义对象时,无参构造方法 使用的是 自然排序 对元素进行排序
    2. 自然排序,就是 让元素所属的类实现Comparable接口,重写compareTo(T o)方法
    3. 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

3.9 比较器排序 Comparator 的使用

  • 需求:
    1. 存储学生对象并遍历,创建TreeSet集合使用 带参构造方法
    2. 按年龄从小到大排序,年龄相同时,按姓名的字母顺序排序
/*
	学生类
 */
 package com.set.TreeSet2;

public class Student {
     
    private String name;
    private int age;
    public Student(){
     }
    public Student(String name, int age) {
     
        this.name = name;
        this.age = age;
    }
    public String getName() {
     
        return name;
    }

    public void setName(String name) {
     
        this.name = name;
    }

    public int getAge() {
     
        return age;
    }

    public void setAge(int age) {
     
        this.age = age;
    }
}

package com.set.TreeSet2;

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

/*
    需求:
        1.存储学生对象并遍历,创建TreeSet集合使用带参构造方法
        2.按年龄从小到大排序,年龄相同时,按姓名的字母顺序排序
 */
public class TreeSetDemo {
     
    public static void main(String[] args){
     
        TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
     
            @Override
            public int compare(Student s1, Student s2) {
     
                int num1 = s1.getAge() - s2.getAge();
                int num2 = num1 == 0 ? s1.getName().compareTo(s2.getName()): num1;
                return num2;
            }
        });
        Student s1 = new Student("苦瓜", 21);
        Student s2 = new Student("半仙儿", 22);
        Student s3 = new Student("守约", 18);
        Student s4 = new Student("卡布奇诺",18);
        Student s5 = new Student("卡布奇诺",18);
        ts.add(s1);
        ts.add(s2);
        ts.add(s3);
        ts.add(s4);
        ts.add(s5);
        for (Student s : ts) {
     
            System.out.println(s.getName() + "," + s.getAge());
        }
    }

}

  • 结论
    1. 用 TreeSet 集合存储自定义对象,带参构造方法使用的是 比较器排序 对元素进行排序
    2. 比较器排序,就是 让集合构造方法接收Comparator的实现类对象 ,重写 compareTo(T o1,T o2)方法
    3. 重写方法时,一定要注意排序规则必须按照要求的主要条件和次要条件来写

4. 泛型

4.1 泛型概述

  • 泛型
    泛型是JDK5中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型;它的本质是 参数化类型 ,也就是说所操作的数据类型被指定为一个参数。一提到参数,最熟悉的就是定义方法时有 形参 ,然后调用此方法时传递 实参 。而参数化类型是 将类型由原来的具体的类型参数化,然后在使用/调用时传入具体的类型。这种参数类型可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口。

  • 泛型定义格式

    1. <类型>:指定一种类型的格式。这里的类型可以看成是形参
    2. <类型1,类型2…>:指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
    3. 将来具体调用的时候给定的类型可以看成是实参,并且实参的类型只能是引用数据类型
  • 泛型的好处:

    1. 将运行时期的问题提前到了编译期
    2. 避免了强制类型转换
package com.Generic;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;

/*
    需求:
        Collection集合存储字符串并遍历
    泛型的好处:
        1. 将运行时期的问题提前到了编译期
        2. 避免了强制类型转换
 */
public class GenericDemo01 {
     
    public static void main(String[] args){
     
        //创建集合对象(暂时先不采用泛型)
//        Collection c = new ArrayList();

        Collection<String> c = new ArrayList<String>();

        //添加元素
        /*
            当我们没有指定集合中元素类型时,默认是Object类型,
            因为泛型默认是引用类型,而Object可以代表所有的引用类型
            我们将字符串赋值给Object就向上转型了
         */
        c.add("苦瓜");
        c.add("半仙儿");
        c.add("粉色匡威");

//        c.add(100);//"100"会自动封装成Integer类型,有个自动装箱的操作
        //遍历
//        Iterator it = c.iterator();
        Iterator<String> it = c.iterator();
        while(it.hasNext()){
     
            /*
                注意这里不是String类型,因为添加的时候String向上转型成了Object
             */
//            Object object = it.next();
//            System.out.println(object);

            //Object向下转型变成String类型
//            String s = (String)it.next();//ClassCastException

            String s = it.next();
            System.out.println(s);
        }
    }
}

4.2 泛型类

  • 泛型类的定义格式
    • 格式:修饰符 class 类名<类型>{ }
    • 范例:public class Generi { }
      此处 T 可以随便写为任意标识,常见的如 T、E、K、V 等形式的参数常用于表示泛型
/*
	学生类
 */
package com.Generic;

public class Student {
     
    private String name;
    public String getName(){
     
        return name;
    }
    public void setName(String name){
     
        this.name = name;
    }
}

/*
	教师类
 */
package com.Generic;

public class Teacher {
     
    private Integer age;
    public Integer getAge(){
     
        return age;
    }
    public void setAge(Integer age){
     
        this.age = age;
    }
}

/*
	泛型类
 */
package com.Generic;

public class Generic<T> {
     
    private T t;

    public T getT() {
     
        return t;
    }

    public void setT(T t) {
     
        this.t = t;
    }
}

package com.Generic;

/*
    测试类
 */
public class GenericDemo02 {
     
    public static void main(String[] args){
     
        Student s1 = new Student();
        s1.setName("苦瓜");
        System.out.println(s1.getName());

        Teacher t1 = new Teacher();
        t1.setAge(21);
        System.out.println(t1.getAge());
        System.out.println("-------");

        Generic<String> g1 = new Generic<String>();
        g1.setT("半仙儿");
        System.out.println(g1.getT());
        Generic<Integer> g2 = new Generic<Integer>();
        g2.setT(22);
        System.out.println(g2.getT());
    }
}

4.3 泛型方法

  • 泛型方法的定义格式:
    1. 格式:修饰符<类型> 返回值类型 方法名(类型 变量名){ }
    2. 范例:public void show(T t){ }
package com.Generic2;

public class Generic {
     
   public void show(String s){
     
       System.out.println(s);
   }
   public void show(Integer i){
     
       System.out.println(i);
   }
   public void show(Boolean b){
     
       System.out.println(b);
   }
   //泛型方法
   public <T> void show(T t){
     
       System.out.println(t);
   }
}

package com.Generic2;

/*
    测试类
 */
public class GenericDemo {
    public static void main(String[] args){
        Generic g = new Generic();
        g.show("苦瓜");
        g.show(376);
        g.show(true);
        System.out.println("-------");
        Generic g2 = new Generic();
        g2.show("半仙儿");
        g2.show(397);
        g2.show(true);
    }
}

4.4 泛型接口

  • 泛型j接口的定义格式
    1. 格式:修饰符 interface 接口名<类型>{ }
    2. 范例:public interface Generic { }
package com.Generic3;
/*
    泛型接口
 */
public interface Generic<T> {
     
    void show(T t);
}

package com.Generic3;
/*
    泛型接口实现类
 */
public class GenericImpl<T> implements Generic<T>{
     
    @Override
    public void show(T t) {
     
        System.out.println(t);
    }
}

package com.Generic3;
/*
    测试类
 */
public class GenericDemo {
     
    public static void main(String[] args){
     
        Generic<String> g1 = new GenericImpl<String>();
        g1.show("半仙儿");
        Generic<Integer> g2 = new GenericImpl<Integer>();
        g2.show(367);
    }
}

4.5 类型通配符

  • 为了表示各种泛型 List 的父类,我们可以使用通配符

    • 类型通配符:
    • List:表示元素类型未知的 List ,它的元素可以匹配 任何的类型
    • 这种带通配符的 List 仅表示各种泛型 List 的父类,并不能把元素添加到其中
  • 如果说我们不希望 List 是任何泛型List的父类,只希望它代表某一类泛型List的父类,可以使用类型通配符的上限

    • 类型通配符上限:
    • List: 它表示的类型是 Number或者其子类型
  • 除了指定类型通配符的上限,我们还可以指定类型通配符的下限

    • 类型通配符下限:
    • List:它表示的类型是 Number或者其父类型
package com.Generic4;

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

/*
    类型通配符:
        List:表示元素类型未知的 List ,它的元素可以匹配 任何的类型
        这种带通配符的 List 仅表示各种泛型 List 的父类,并不能把元素添加到其中
    类型通配符上限:
        List: 它表示的类型是 Number或者其子类型
    类型通配符下限:
        List:它表示的类型是 Number或者其父类型

    Integer的父类是Number,Number的父类是Object
 */
public class GenericDemo01 {
     
    public static void main(String[] args){
     
        //类型通配符:
        List<?> list1 = new ArrayList<Object>();
        List<?> list2 = new ArrayList<Number>();
        List<?> list3 = new ArrayList<Integer>();
        System.out.println("-------");
        //类型通配符上限:
//        List list4 = new ArrayList();//报错
        List<? extends Number> list5 = new ArrayList<Number>();
        List<? extends Number> list6 = new ArrayList<Integer>();
        System.out.println("-------");
        //类型通配符下限:
        List<? super Number> list7 = new ArrayList<Object>();
        List<? super Number> list8 = new ArrayList<Number>();
//        List list9 = new ArrayList();//报错

    }
}

 
  

4.6 可变参数

  • 可变参数又称为参数个数可变,用作方法的形参出现,那么方法参数个数就是可变的了
    • 格式:修饰符 返回值类型 方法名(数据类型… 变量名){ }
    • 范例:public static int sum(int… a){ }
package com.Args;
/*
    测试类
 */
public class ArgsDemo01 {
     
    public static void main(String[] args){
     
        System.out.println(sum(70,110));
        System.out.println(sum(65,100,110));
        System.out.println(sum(70,65,110,110));
    }
//    public static int sum(int a,int b){
     
//        return a + b;
//    }
//    public static int sum(int a,int b,int c){
     
//        return a + b + c;
//    }
//    public static int sum(int a,int b,int c,int d){
     
//        return a + b + c + d;
//    }
    //可变参数
    public static int sum(int... a){
     //这里a其实是一个数组
        int sum = 0;
        for(int i : a){
     
            sum += i;
        }
        return sum;
    }
    //当一个方法有多个参数且包含可变参数时,可变参数要放在最后
//    public static int sum(int b,int... a){
     
//        return 0;
//    }
}

  • 可变参数注意事项:
    • 这里的变量其实是一个数组
    • 如果一个方法有多个参数,且包含可变参数,可变参数要放在最后

4.7 可变参数的使用

  • Arrays 工具类中有一个静态方法:
    • public static List asList(T… a):返回由指定数组支持的固定大小的列表
    • 返回的集合不能做增删操作,可以做修改操作
  • List 接口中能够有一个静态方法:
    • public static List of(E… elements):返回包含任意数量元素的不可变列表
    • 返回的集合不能做增删改操作
  • Set 接口中有一个静态方法:
    • public static Set of(E… elements):返回一个包含任意数量元素的不可变集合
    • 在给元素的时候,不能给重复的元素
    • 返回的集合不能做增删操作,没有修改的方法
package com.Args;


import java.util.Arrays;
import java.util.List;
import java.util.Set;

/*
    Arrays 工具类中有一个静态方法:
        public static  List  asList(T… a):
        返回由指定数组支持的固定大小的列表
    List 接口中能够有一个静态方法:
        public static  List  of(E… elements):
        返回包含任意数量元素的不可变列表
    Set 接口中有一个静态方法:
        public static  Set of(E… elements):
        返回一个包含任意数量元素的不可变集合
 */
public class ArgsDemo02 {
     
    public static void main(String[] args){
     
        //public static  List  asList(T… a):返回由指定数组支持的固定大小的列表
//        List list = Arrays.asList("苦瓜", "半仙儿", "粉色匡威");
        list.add("bug"); //UnsupportedOperationException 不支持请求的操作
        list.remove("苦瓜"); //UnsupportedOperationException
//        list.set(0,"njust");
//        System.out.println(list);

        //public static  List  of(E… elements):返回包含任意数量元素的不可变列表
//        List.of("苦瓜","半仙儿","粉色匡威");//jdk9新特性
        list.add("bug"); //UnsupportedOperationException
        list.remove("苦瓜"); //UnsupportedOperationException
        list.set(0,"njust");//UnsupportedOperationException
//        System.out.println(list);

        //public static  Set of(E… elements):返回一个包含任意数量元素的不可变集合
        Set set = new  Set.of("苦瓜","半仙儿","粉色匡威","苦瓜");//IllegalArgumentException
//        Set set = new  Set.of("苦瓜","半仙儿","粉色匡威");
        set.add("bug"); //UnsupportedOperationException
        set.remove("苦瓜"); //UnsupportedOperationException
//        System.out.println(set);
    }
}

5. Map

5.1 Map 集合概述和使用

  • Map 集合概述
    • Interface Map
      K:键的类型
      V:值的类型
    • 它是将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值
    • 举例:学生的学号和姓名
      1418001 ------- 苦瓜
      1418002 ------- 半仙儿
      1418003 ------- 粉色匡威
  • 创建 Map集合的对象
    • 采用多态的方式
    • 使用具体的实现类 HashMap
package com.Map;

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

/*
    Map 集合概述
        Interface Map
        K:键的类型
        V:值的类型
        它是将键映射到值的对象;不能包含重复的键;每个键可以映射到最多一个值
        举例:学生的学号和姓名
        1418001 ------- 苦瓜
        1418002 ------- 半仙儿
        1418003 ------- 粉色匡威
    创建 Map集合的对象
        采用多态的方式
        使用具体的实现类 HashMap
 */
public class MapDemo01 {
     
    public static void main(String[] args){
     
        //创建集合对象
        Map<String,String> map = new HashMap<String,String>();
        //put(K key,V value):将指定的值与该映射中的指定键相关联
        map.put("1418001","苦瓜");
        map.put("1418002","半仙儿");
        map.put("1418003","粉色匡威");
        map.put("1418003","njust");//键是唯一的,第二次出现时会修改之前的值

        //输出集合对象
        System.out.println(map);
    }
}

5.2 Map 集合的基本功能

JavaSE 集合进阶_第22张图片

package com.Map;

import java.util.HashMap;
import java.util.Map;
/*
    Map集合的基本功能:
        V put(K key,V value):添加元素
        V remove(Object key):根据键删除键值对元素
        void clear():移除所有的键值对元素
        boolean containsKey(Object key):判断集合是否包含指定的键
        boolean containsValue(Object value):判断集合是否包含指定的值
        boolean isEmpty():判断集合是否为空
        int size():集合的长度,也就是集合中键值对的个数

 */
public class MapDemo02 {
     
    public static void main(String[] args){
     
        Map<String,String> map = new HashMap<String,String>();
        //V put(K key,V value):添加元素
        map.put("苦瓜","hnist");
        map.put("半仙儿","njust");
        map.put("粉色匡威","樱花卡西欧");

        //V remove(Object key):根据键删除键值对元素
//        System.out.println(map.remove("粉色匡威"));
        //void clear():移除所有的键值对元素
//        map.clear();
        //boolean containsKey(Object key):判断集合是否包含指定的键
//        System.out.println(map.containsKey("半仙儿"));
//        System.out.println(map.containsKey("卡布奇诺"));
        //boolean isEmpty():判断集合是否为空
        System.out.println(map.isEmpty());
        //int size():集合的长度,也就是集合中键值对的个数
        System.out.println(map.size());

        System.out.println(map);
    }
}

5.3 Map集合的获取功能

JavaSE 集合进阶_第23张图片

package com.Map;

import java.util.HashMap;
import java.util.Map;
/*
    Map集合的获取功能:
        V get(Object key):根据键获取值
        Set keySet():获取所有键的集合
        Collection values():获取所有值的集合
 */
public class MapDemo03 {
     
    public static void main(String[] args){
     
        Map<String,String> map = new HashMap<String,String>();
        map.put("苦瓜","hnist");
        map.put("半仙儿","njust");
        map.put("bug工程师","bug");

        //V get(Object key):根据键获取值
        System.out.println(map.get("半仙儿"));
        //Set keySet():获取所有键的集合
        System.out.println(map.keySet());
        //Collection values():获取所有值的集合
        System.out.println(map.values());
    }
}

5.4 Map 集合的遍历(方式1)

  • Map 集合中存储的元素都是成对出现的,可以把 Map 看成是一个夫妻对的集合
  1. 遍历思路:
    • 把所有的丈夫集中起来
    • 遍历丈夫的集合,获取到每一个丈夫
    • 根据丈夫去找对应的妻子
  2. 转换为Map集合中的操作
    • 获取所有键的集合。用keySet()方法实现
    • 遍历键的集合,获取到每一个键。用增强for实现
    • 根据键去找值。用 get(Object key)方法实现
package com.Map;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/*
     Map 集合的遍历(方式1):
        1.获取所有键的集合。用keySet()方法实现
        2.遍历键的集合,获取到每一个键。用增强for实现
        3.根据键去找值。用 get(Object key)方法实现
 */
public class MapDemo04 {
     
    public static void main(String[] args){
     
        Map<String,String> map = new HashMap<String,String>();
        map.put("苦瓜","hnist");
        map.put("半仙儿","njust");
        map.put("粉色匡威","樱花卡西欧");

        // 1.获取所有键的集合。用keySet()方法实现
        Set<String> keySet = map.keySet();
        //2.遍历键的集合,获取到每一个键。用增强for实现
        for(String key : keySet){
     
            //3.根据键去找值。用 get(Object key)方法实现
            String value = map.get(key);
            System.out.println(key + "-----" + value);
        }
    }
}


5.5 Map 集合的遍历(方式2)

  • Map 集合中存储的元素都是成对出现的,可以把 Map 看成是一个夫妻对的集合
  1. 遍历思路:
    • 获取所有结婚证的集合
    • 遍历结婚证的集合,获取每一个结婚证
    • 根据结婚证获取丈夫和妻子
  2. 转换为Map集合中的操作
    • 获取所有键值对对象的集合
      set> entrySet():获取所有键值对对象的集合
    • 遍历键值对对象集合,得到每一个键值对对象
      用增强for实现,得到每一个 Map.Entry
    • 根据键值对对象获取键和值
      用 getKey()方法获取键
      用 getValue()方法获取值
package com.Map;

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

/*
    Map 集合的遍历(方式2):
        1.获取所有键值对对象的集合
            set> entrySet():获取所有键值对对象的集合
        2.遍历键值对对象集合,得到每一个键值对对象
            用增强for实现,得到每一个 Map.Entry
        3.根据键值对对象获取键和值
            用 getKey()方法获取键
            用 getValue()方法获取值
 */
public class MapDemo05 {
     
    public static void main(String[] args){
     
        Map<String,String> map = new HashMap<String,String>();
        map.put("苦瓜","hnist");
        map.put("半仙儿","njust");
        map.put("bug开发师","bug");

        //1.获取所有键值对对象的集合
        Set<Map.Entry<String, String>> entrySet = map.entrySet();
        //2.遍历键值对对象集合,得到每一个键值对对象
        for(Map.Entry<String, String> entry : entrySet){
     
            //3.根据键值对对象获取键和值
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "-----" + value);
        }
    }
}

6. Collections

6.1 Collections 概述和使用

  • 概述
    • Collections 类是针对集合操作的工具类
  • Collections 类的常用方法
    • public static > void sort(List list):将指定的列表按升序排序
    • public static viod reverse(List list):反转指定列表中元素的顺序
    • public static void shuffle(List list):使用默认的随机源随机排列指定的列表
package com.Collections;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/*
    Collections类概述
        Collections类是针对集合操作的工具类
    Collections 类的常用方法
        public static > void sort(List list):将指定的列表按升序排序
        public static viod reverse(List list):反转指定列表中元素的顺序
        public static void shuffle(List list):使用默认的随机源随机排列指定的列表
 */
public class CollectionsDemo01 {
     
    public static void main(String[] args){
     
        List<Integer> list = new ArrayList<Integer>();
        list.add(70);
        list.add(65);
        list.add(115);
        list.add(110);
        list.add(376);
        Collections.sort(list);
        Collections.reverse(list);
        Collections.shuffle(list);
        System.out.println(list);
    }
}

6.2 模拟斗地主

package com.Poker;

import java.util.ArrayList;
import java.util.Collections;

/*
    需求:
        通过程序实现斗地主过程中的洗牌,发牌和看牌
    思路:
        1.创建一个牌盒,也就是定义一个集合对象,用ArrayList集合实现
        2.往牌盒里面装牌
        3.洗牌,也就是把牌打散,用Collectons的shuffle()方法实现
        4.发牌,也就是遍历集合,给三个玩家发牌
        5.看牌,也就是三个玩家分别遍历自己的牌
 */
public class PokerDemo01 {
     
    public static void main(String[] args){
     
        //1.创建一个牌盒,也就是定义一个集合对象,用ArrayList集合实现
        ArrayList<String> array = new ArrayList<String>();
        //2.往牌盒里面装牌
        /*
            ♦2,♦3...♦K,♦A
            ♣2...
            ♥2...
            ♠2...
            大王,小王
         */
        //定义花色数组
        String[] colors = {
     "♦","♣","♥","♠"};
        //定义点数数组
        String[] numbers = {
     "2","3","4","5","6","7","8","9","10","J","Q","K","A"};
        for(String color : colors){
     
            for(String number : numbers){
     
                array.add(color + number);
            }
        }
        array.add("大王");
        array.add("小王");

        //3.洗牌,也就是把牌打散,用Collectons的shuffle()方法实现
        Collections.shuffle(array);
//        System.out.println(array);
        //4.发牌,也就是遍历集合,给三个玩家发牌
        ArrayList<String> kgArray = new ArrayList<String>();//三个玩家
        ArrayList<String> bxArray = new ArrayList<String>();
        ArrayList<String> fhArray = new ArrayList<String>();
        ArrayList<String> dpArray = new ArrayList<String>();//底牌3张

        for(int i = 0;i < array.size();i++){
     
            String poker = array.get(i);
            if(i >=array.size()-3){
     
                dpArray.add(poker);
            }else if(i % 3 == 0){
     
                kgArray.add(poker);
            }else if(i % 3 == 1){
     
                bxArray.add(poker);
            }else if(i % 3 == 2){
     
                fhArray.add(poker);
            }
        }

        //5.看牌,也就是三个玩家分别遍历自己的牌
        lookPoker("苦瓜",kgArray);
        lookPoker("半仙儿",bxArray);
        lookPoker("bug工程师",fhArray);
        lookPoker("底牌",dpArray);
    }
    //看牌的方法
    public static void lookPoker(String name,ArrayList<String> array){
     
        System.out.print(name + "的牌是:");
        for(String poker : array){
     
            System.out.print(poker + "  ");
        }
        System.out.println();
    }
}

JavaSE 集合进阶_第24张图片

6.3 模拟斗地主(升级版)

JavaSE 集合进阶_第25张图片

package com.Poker;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;

/*
    需求:
        通过程序实现模拟斗地主过程中的洗牌,发牌和看牌
    要求:
        对牌进行排序
    思路;
        1.创建HashMap集合,键是编号,值是牌
        2.创建ArrayList集合,存储编号
        3.创建花色数组和点数数组
        4.从0开始往HashMap里面存储编号,并存储对应的牌。同时往ArrayList里面存储编号
        5.洗牌(洗的是编号),用Collections的shuffle()方法实现
        6.发牌(发的也是编号,为了保证编号是排序的,创建TreeSet集合接收)
        7.定义方法看牌(遍历TreeSet集合,获取编号,然后根据编号到HashMap集合找对应的牌)
        8.调用看牌方法
 */
public class PokerDemo02 {
     
    public static void main(String[] args){
     
        //1.创建HashMap集合,键是编号,值是牌
        HashMap<Integer,String> hm = new HashMap<Integer, String>();
        //2.创建ArrayList集合,存储编号
        ArrayList<Integer> array = new ArrayList<Integer>();
        //3.创建花色数组和点数数组
        String[] colors = {
     "♦","♣","♥","♠"};
        String[] numbers = {
     "3","4","5","6","7","8","9","10","J","Q","K","A","2"};

        //4.从0开始往HashMap里面存储编号,并存储对应的牌。同时往ArrayList里面存储编号
        int index = 0;
        for(String color : colors){
     
            for(String number : numbers){
     
                hm.put(index,color+number);
                array.add(index);
                index++;
            }
        }
        hm.put(index,"小王");
        array.add(index);
        index++;
        hm.put(index,"大王");
        array.add(index);

        //5.洗牌(洗的是编号),用Collections的shuffle()方法实现
        Collections.shuffle(array);

        //发牌(发的也是编号,为了保证编号是排序的,创建TreeSet集合接收)
        TreeSet<Integer> kgSet = new TreeSet<Integer>();
        TreeSet<Integer> bxSet = new TreeSet<Integer>();
        TreeSet<Integer> fhSet = new TreeSet<Integer>();
        TreeSet<Integer> dpSet = new TreeSet<Integer>();

        for(int i=0;i<array.size();i++){
     
            int x = array.get(i);
            if(i>=array.size()-3){
     
                dpSet.add(x);
            }else if(i % 3 == 0){
     
                kgSet.add(x);
            }else if(i % 3 == 1){
     
                bxSet.add(x);
            }else if(i % 3 == 2){
     
                fhSet.add(x);
            }
        }

        //8.调用看牌方法
        lookPoker("苦瓜",kgSet,hm);
        lookPoker("半仙儿",bxSet,hm);
        lookPoker("bug开发师",fhSet,hm);
        lookPoker("底牌",dpSet,hm);
    }
    //7.定义方法看牌(遍历TreeSet集合,获取编号,然后根据编号到HashMap集合找对应的牌)
    public static void lookPoker(String name,TreeSet<Integer> ts,HashMap<Integer,String> hm){
     
        System.out.print(name + "的牌是:");
        for(Integer key : ts){
     
            String poker = hm.get(key);
            System.out.print(poker + "  ");
        }
        System.out.println();
    }
}

JavaSE 集合进阶_第26张图片

你可能感兴趣的:(JavaSE,java,javase)