Java教程

JAVA-集合

本文主要是介绍JAVA-集合,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

第一节 Collection集合

1.1 集合框架介绍

在这里插入图片描述

1.2 Collection集合常用功能

java.util.Collection接口
所有单列集合的最顶层的接口,里边定义了所有单列集合共性的方法
任意的单列集合都可以使用Collection接口中的方法

共性的方法:
public boolean add(E e):把给定的对象添加到当前集合中
public void clear():清空集合中所有的集合
public boolean remove(E e):把给定的对象在当前集合中删除
public boolean contains(E e):判断当前集合中是否包含给定的对象
public boolean isEmpty():判断当前集合是否为空
public int size():返回集合中元素的个数
public Object[] toArray():把集合中的元素,存储到数组中

1.3 Iterator接口

java.util.Iterator接口:迭代器(对集合进行遍历)

有两个常用方法:
boolean hasNext():如果仍有元素可以迭代,则返回true
判断集合中还有没有下一个元素,有就返回true,没有就返回false
E next():返回迭代的下一个元素
取出集合中的下一个元素

Iterator迭代器,是一个接口,我们无法直接使用,需要使用Iterator接口的实现类对象,获取实现类的方式比较特殊
Collection接口中有一个方法,叫iterator(),这个方法返回的就是迭代器的实现类对象

迭代器的使用步骤:
1、使用集合中的方法iterator()获取迭代器的实现类对象,使用Iterator接口接收(多态)
2、使用Iterator接口中的方法hasNext判断还有没有下一个元素
3、使用Iterator接口中的方法next取出集合中的下一个元素

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class Demo02Iterator {
    public static void main(String[] args) {
    	//多态
        Collection<String> coll = new ArrayList<>();
        coll.add("小松狮");
        coll.add("小锦鲤");
        Iterator<String> it = coll.iterator();
        /*
        boolean b = it.hasNext();
        String s = it.next();
        System.out.println(s);
        */
        //发现使用迭代器取出集合中元素的代码,是一个重复的过程
        //        所以我们可以使用循环优化
        //        不知道集合中有多少元素,使用while循环
        //        循环结束的条件,hasNext方法返回false
        while(it.hasNext()){
            String e = it.next();
            System.out.println(e);
        }
    }
}

1.4 增强for循环

增强for循环:底层使用的也是迭代器,使用for循环的格式,简化了迭代器的书写
Collection extends Iterable:所有的单列集合都可以使用增强for
public interface Iterable实现这个接口允许对象成为“foreach”语句的目标
增强for循环:用来遍历集合和数组

格式:
for(集合/数组的数据类型 变量名 :集合名/数组名){
System.out.println(变量名);
}

public class Demo03Foreach {
    public static void main(String[] args) {
        demo01();
        demo02();
    }
    //使用增强for循环遍历集合
    private static void demo02() {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("小松狮");
        arrayList.add("小锦鲤");
        arrayList.add("小松狮1");
        arrayList.add("小锦鲤1");
        for (String b : arrayList) {
            System.out.println(b);
        }
    }
    //使用增强for循环遍历数组
    private static void demo01() {
        int[] array = {1, 2, 3, 4, 5};
        for (int a : array){
            System.out.println(a);
        }
    }
}

第二节 泛型

泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型
泛型也可以看做是一个变量,用来接收数据类型
E e:Element 元素
T t:Type 类型
ArrayList集合在定义的时候,不知道集合中都会存储什么类型的数据,所以类型使用泛型
E:未知的数据类型

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

public class Demo01Generic {
    public static void main(String[] args) {
        demo01();
        demo02();
    }
    /*
    创建集合对象,使用泛型
    好处:
    1、避免了类型转换的麻烦,存储的是什么类型,取出的就是什么类型
    2、把运行期异常提升到了编译期
    弊端:泛型是什么类型,只能存储什么类型的数据
     */
    private static void demo02() {
        ArrayList<String> list = new ArrayList<>();
        list.add("小松狮");
        //list.add(111);
        list.add("小锦鲤");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            System.out.println(next);
        }
    }
    /*
    * 创建集合对象,不使用泛型
    * 好处:集合不使用泛型,默认的类型就是Object类型,可以存储任意类型的数据
    * 弊端:不安全,会引发异常
    * */
    private static void demo01() {
        ArrayList list = new ArrayList();
        list.add("小松狮");
        list.add(123);
        Iterator it1 = list.iterator();
        while (it1.hasNext()){
            Object next = it1.next();
            System.out.println(next);
            //想要使用String类特有的方法,length获取字符串的长度;不能使用
            //需向下转型
            //会抛出ClassCastException
            //String s = (String) next;
            //System.out.println(s.length());
        }
    }
}

2.1 定义和使用含有泛型的类

定义一个含有泛型的类,模拟ArrayList集合
泛型是一个未知的数据类型,当我们不确定什么数据类型的时候,可以使用泛型
泛型可以接受任意数据类型,可以使用Integer,String,Student…
创建对象的时候确定泛型的数据类型

public class Demo02Generic<E> {
    private E name;

    public E getName() {
        return name;
    }

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

public class Demo03Generic {
    public static void main(String[] args) {
        Demo02Generic gc = new Demo02Generic();
        gc.setName("字符串");
        Object name = gc.getName();
        System.out.println(name);
        Demo02Generic<Integer> gc2 = new Demo02Generic<>();
        gc2.setName(222);
        Integer name1 = gc2.getName();
        System.out.println(name1);
        Demo02Generic<String> gc3 = new Demo02Generic<>();
        gc3.setName("小松狮");
        String name2 = gc3.getName();
        System.out.println(name2);
    }
}

2.2 定义和使用含有泛型的方法

定义含有泛型的方法:泛型定义在方法的修饰符和返回值类型之间

格式:
修饰符<泛型> 返回值类型 方法名(参数列表(使用泛型)){
方法体;
}

含有泛型的方法,在调用方法的时候确定泛型的数据类型
传递什么类型的参数,泛型就是什么类型

public class GenericMethod {
    //定义一个含有泛型的方法
    public <M> void method01(M m){
        System.out.println(m);
    }
    //定义一个含有泛型的静态方法
    public static <S> void method02(S s){
        System.out.println(s);
    }
}
public class Demo04GenericMethod {
    public static void main(String[] args) {
        //创建一个GenericMethod对象
        GenericMethod gm = new GenericMethod();
        gm.method01(123);
        gm.method01("小松狮");
        gm.method01(3.14);
        gm.method01(true);
        gm.method02("静态方法,不建议创建对象使用");
        //静态方法通过类名.方法名(参数)可以直接使用
        GenericMethod.method02("静态方法");
        GenericMethod.method02(123);
    }
}

2.3 定义和使用含有泛型的接口

/*
定义含有泛型的接口
 */
public interface GenericInterface<I> {
    public abstract void method(I i);
}
/*
含有泛型的接口,第一种使用方式:
定义接口的实现类,实现接口,指定接口的泛型
 */
public class GenericInterfaceImpl1 implements GenericInterface<String>{

    @Override
    public void method(String s) {
        System.out.println(s);
    }
}
/*
含有泛型的接口,第二种使用方式:
接口使用什么泛型,实现类就使用什么泛型,类跟着接口走
就相当于定义了一个含有泛型的类,创建对象的时候确定泛型的类型
 */
public class GenericInterfaceImpl2<I> implements GenericInterface<I>{

    @Override
    public void method(I i) {
        System.out.println(i);
    }
}
/*
定义含有泛型的方法:泛型定义在方法的修饰符和返回值类型之间
格式:
修饰符<泛型> 返回值类型 方法名(参数列表(使用泛型)){
方法体;
}
含有泛型的方法,在调用方法的时候确定泛型的数据类型
传递什么类型的参数,泛型就是什么类型
 */
public class GenericMethod {
    //定义一个含有泛型的方法
    public <M> void method01(M m){
        System.out.println(m);
    }
    //定义一个含有泛型的静态方法
    public static <S> void method02(S s){
        System.out.println(s);
    }
}

2.4 泛型通配符

泛型的通配符:
?:代表任意的数据类型
使用方法:
不能创建对象使用
只能作为方法的参数使用

public class Demo06Generic {
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(1);
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("小松狮");
        printList(list1);
        printList(list2);
//        ArrayList<?> list3 = new ArrayList<?>();错误写法!
    }
    /*
    定义一个方法,能遍历所有类型的ArrayList集合
    这时候我们不知道ArrayList集合使用什么数据类型,可以使用泛型的通配符?来接受数据类型
    注意:泛型没有继承概念的
     */
    public static void printList(ArrayList<?> list){
        Iterator<?> it = list.iterator();
        while (it.hasNext()){
            //取出的元素是Object,可以接收任意的数据类型
            Object next = it.next();
            System.out.println(next);
        }
    }
}

泛型的上限限定:?extends E 代表使用的泛型只能是E类型的子类/本身
泛型的下限限定:?super E 代表使用的泛型只能是E类型的父类/本身

2.5 斗地主案例

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

/*
斗地主案例:
1、准备牌
2、洗牌
3、发牌
4、看牌
 */
public class DouDiZhu {
    public static void main(String[] args) {
        //1、准备牌
        //定义一个存储54张牌的ArrayList集合,泛型使用String
        ArrayList<String> poker = new ArrayList<>();
        //定义两个数组,一个数组存储牌的花色,一个数组存储牌的序号
        String[] colors = {"♠", "♥", "♣", "♦"};
        String[] numbers = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"};
        //先把大王和小王存储到poker集合中
        poker.add("大王");
        poker.add("小王");
        //循环嵌套遍历两个数组,组装52张牌
        for (String number : numbers){
            for (String color : colors){
                //System.out.println(color + number);
                //把组装好的牌存储到poker集合中
                poker.add(color + number);
            }
        }
        //2、洗牌
        //使用集合的工具类Collections中的方法
        //static void shuffle(List<?> List)
        Collections.shuffle(poker);
        //System.out.println(poker);
        //3、发牌
        //定义4个集合,存储玩家的牌和底牌
        ArrayList<String> player01 = new ArrayList<>();
        ArrayList<String> player02 = new ArrayList<>();
        ArrayList<String> player03 = new ArrayList<>();
        ArrayList<String> diPai = new ArrayList<>();
        /*
        遍历poker集合,获取每一张牌
        使用poker集合的索引%3给3个玩家轮流发牌
        剩余3张牌给底牌
        注意:先判断底牌(i>=51),否则牌就发完了
         */
        for (int i = 0; i < poker.size(); i++){
            //获取每一张牌
            String p = poker.get(i);
            //轮流发牌
            if (i >= 51){
                diPai.add(p);
            }else if (i % 3 == 0){
                player01.add(p);
            }else if (i % 3 == 1){
                player02.add(p);
            }else if (i % 3 == 2){
                player03.add(p);
            }
        }
        //4、看牌
        System.out.println("赌神:" + player01);
        System.out.println("赌侠:" + player02);
        System.out.println("赌圣:" + player03);
        System.out.println("底牌:" + diPai);
    }
}

第三节 List集合

3.1 List集合

java.util.List接口extends Collection接口
List接口的特点:
1、有序的集合,存储元素和取出元素的顺序是一致的(存储123 取出123)
2、有索引,包含了一些带索引的方法
3、允许存储重复的元素

List接口中带索引的方法(特有)
public void add(int index, E element):将指定的元素,添加到该集合中的指定位置上
public E get (int index):返回集合中指定位置的元素
public E remove(int index):移除列表中指定位置的元素,返回的是被移除的元素
public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值是更新前的元素
注意:
操作索引的时候,一定要防止索引越界异常
IndexOutOfBoundsException:索引越界异常

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Demo01List {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("小松狮");
        list.add("小锦鲤");
        list.add("小松狮1");
        list.add("小锦鲤1");
        System.out.println(list);
        list.add(2,"哈喽");
        System.out.println(list);
        String remove = list.remove(3);
        System.out.println(remove);
        System.out.println(list);
        String set = list.set(2, "小松狮1");
        System.out.println(set);
        System.out.println(list);
        //List集合的三种遍历
        //普通for循环
        for (int i = 0; i < list.size(); i++){
            String s = list.get(i);
            System.out.println(s);
        }
        //使用迭代器
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String next = iterator.next();
            System.out.println(next);
        }
        //使用增强for循环
        for (String s: list) {
            System.out.println(s);
        }
    }
}

3.2 ArrayList集合

java.util.LinkedList集合 implements List接口
LinkedList集合的特点:
1、底层是一个链表结构:查询慢,增删快
2、里边包含了大量操作首尾元素的方法
注意:使用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 Demo02LinkedList {
    public static void main(String[] args) {
        demo01();
        demo02();
        demo03();
    }

    private static void demo03() {
        LinkedList<String> linked = new LinkedList();
        linked.add("小松狮");
        linked.add("小锦鲤");
        linked.add("小松狮1");
        linked.add("小锦鲤1");
        System.out.println(linked);
        String s = linked.removeFirst();//等效于pop();
        System.out.println(s);
        String s1 = linked.removeLast();
        System.out.println(s1);
    }

    private static void demo02() {
        LinkedList<String> linked = new LinkedList();
        linked.add("小松狮");
        linked.add("小锦鲤");
        linked.add("小松狮1");
        linked.add("小锦鲤1");
        System.out.println(linked);
        if (!linked.isEmpty()) {
            String first = linked.getFirst();
            System.out.println(first);
            String last = linked.getLast();
            System.out.println(last);
        }
    }

    private static void demo01() {
        LinkedList<String> linked = new LinkedList();
        linked.add("小松狮");
        linked.add("小锦鲤");
        linked.add("小松狮1");
        linked.add("小锦鲤1");
        System.out.println(linked);
        linked.addFirst("111");//等效于push();
        linked.addLast("333");
        System.out.println(linked);
    }
}

第四节 Set集合

java.util.Set接口 extends Collection接口

Set接口的特点:
1、不允许存储重复的元素
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历

java.util.HashSet集合 implements Set接口

HashSet特点:
1、不允许存储重复的元素
2、没有索引,没有带索引的方法,也不能使用普通的for循环遍历
3、是一个无序的集合,存储元素和取出元素的顺序有可能不一致
4、底层是一个哈希表结构(查询的速度非常快)

public class Demo01Set {
    public static void main(String[] args) {
        Set<Integer> set = new HashSet<>();
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(1);
        Iterator<Integer> iterator = set.iterator();
        while (iterator.hasNext()){
            Integer next = iterator.next();
            System.out.println(next);
        }
        for (Integer i : set){
            System.out.println(i);
        }
    }
}

4.1 哈希值

哈希值:是一个十进制的整数,由系统随机给出
(就是对象的地址值,是一个逻辑地址,模拟出来的地址,不是数据实际存储的物理地址)
在Object类有一个方法,可以获取对象的哈希值

int hashCode()返回该对象的哈希码值

public class Demo02HashCode {
    public static void main(String[] args) {
        Person one = new Person();
        int i = one.hashCode();
        System.out.println(i);//2003749087
        Person two = new Person();
        int i1 = two.hashCode();
        System.out.println(i1);//1324119927
        System.out.println(one);//Day13.Demo04.Person@776ec8df
        System.out.println(two);//Day13.Demo04.Person@4eec7777
        System.out.println(one == two);//false
    }
}

Set集合不允许存储重复元素的原理
Set集合在调用add方法的时候,add方法会调用元素的hashCode方法和equals发给发,判断元素是否重复
前提:存储的元素必须重写hashCode方法和equals方法

4.2 HashSet存储自定义类型元素

import java.util.Objects;

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

    public Person() {
    }

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

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

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", 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;
    }
}
import java.util.HashSet;

/*
HashSet存储自定义类型元素
要求:
同名同年龄的人,视为同一个人,只能存储一次
 */
public class Demo04HashSetSavePerson {
    public static void main(String[] args) {
        HashSet<Person> set = new HashSet<>();
        Person one = new Person("小松狮",18);
        Person two = new Person("小锦鲤",18);
        Person three = new Person("小松狮",18);
        set.add(one);
        set.add(two);
        set.add(three);
        System.out.println(set);
    }
}

4.3 LinkedHashSet集合

java.util.LinkedHashSet集合 extends HashSet集合
LinkedHashSet集合特点:
底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表(记录元素的存储顺序),保证元素有序

public class Demo05LinkedHashSet {
    public static void main(String[] args) {
        HashSet<String> set = new HashSet<>();
        set.add("abc");
        set.add("123");
        set.add("123");
        set.add("小松狮");
        System.out.println(set);//[123, abc, 小松狮] 无序,不允许重复
        LinkedHashSet<String> linked = new LinkedHashSet<>();
        linked.add("123");
        linked.add("abc");
        linked.add("abc");
        linked.add("小锦鲤");
        System.out.println(linked);//[123, abc, 小锦鲤] 有序,不允许重复
    }
}

4.4 可变参数

可变参数
使用前提:当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
使用格式:定义方法时使用
修饰符 返回值类型 方法名(数据类型…变量名){}
可变参数的原理:
可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组,来存储这些参数
传递的参数个数,可以是0个(不传递),1,2,…多个

注意事项:
1、一个方法的参数列表,只能有一个可变参数
2、如果方法的参数有多个,那么可变参数必须卸载参数列表的末尾

public class Demo06VarArgs {
    public static void main(String[] args) {
        int num = add(1);
        int num2 = add(1, 2, 3);
        System.out.println(num2);
    }
    /*
    定义计算(0-n)个整数和的方法
    已知:计算整数的和,数据类型已经确定int
    但是参数的个数不确定,不知道要计算几个整数的和,就可以使用可变参数
     */
    public static int add(int ... arr){
        int sum = 0;
        for (int i: arr) {
            sum += i;
        }
        return sum;
    }
    //public static int method(int ...a, String ... b){

    //}错误!
    //public static int method(String b, double c, int ... a){

    //?正确
}

第五节 Collections工具类

java.util.Collections是集合工具类,用来对集合进行操作,部分方法如下:
public static boolean addAll(Collections c, T… elements):往集合中添加一些元素
public static void shuffle(List<?> list)打乱集合顺序

public class Demo01Collections {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a", "b", "c", "d");
        System.out.println(list);//[a, b, c, d]
        Collections.shuffle(list);
        System.out.println(list);//[d, b, a, c]
    }
}

public static void sort(List<?> list):将集合中元素按照默认规则排序
sort使用前提:被排序的集合里边存储的元素,必须实现Comparable,重写接口中的方法compareTo定义排序的规则
Comparable接口的排序规则:
自己(this)-参数:升序

public class Person implements Comparable<Person>{
    private String name;
    private int age;

    public Person() {
    }

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

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", 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(Person o) {
        //return 0;认为元素都是相同的
        return this.getAge() - o.getAge();//升序
        //return o.getAge() - this.getAge();//降序
    }
}
public class Demo01Collections {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        Collections.addAll(list,"a", "b", "c", "d");
        Collections.shuffle(list);
        System.out.println("=========");
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(6);
        list1.add(3);
        Collections.sort(list1);
        System.out.println(list1);//[1, 3, 6]默认升序
        ArrayList<String> list2 = new ArrayList<>();
        list2.add("a");
        list2.add("A");
        list2.add("t");
        Collections.sort(list2);
        System.out.println(list2);//[A, a, t]
        ArrayList<Person> list3 = new ArrayList<>();
        list3.add(new Person("小松狮",18));
        list3.add(new Person("小松狮",16));
        list3.add(new Person("小松狮",20));
        Collections.sort(list3);
        System.out.println(list3);
    }
}

将集合中元素按照指定规则排序
public static void sort(List list, Comparator<? super T>)
Comparator和Comparable区别:
Comparable:自己(this)和别人(参数)比较,自己需要实现Comparable接口,重写比较的规则compareTo方法
Comparator:相当于找一个第三方来比较
Comparator的排序规则:
o1-o2:升序;o2-o1:降序

public class Demo02Sort {
    public static void main(String[] args) {
        ArrayList<Integer> list1 = new ArrayList<>();
        list1.add(1);
        list1.add(6);
        list1.add(3);
        Collections.sort(list1, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2 - o1;//降序
            }
        });
        System.out.println(list1);//[6, 3, 1]
        ArrayList<Student> list2 = new ArrayList<>();
        list2.add(new Student("小松狮",18));
        list2.add(new Student("小松狮",16));
        list2.add(new Student("小松狮",20));
        Collections.sort(list2, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge();
            }
        });
        System.out.println(list2);
    }
}

第六节 Map集合

java.util.Map<k,v>集合
Map集合的特点:
1、Map集合是一个双列集合,一个元素包含两个值(一个key,一个value)
2、Map集合中的元素,key和value的数据类型可以相同,也可以不同
3、Map集合中的元素,key是不允许重复的,value是可以重复的
4、Map集合中的元素,key和value是一一对应

6.1 Map常用子类

java.util.HashMap<k,v>集合 implements Map<k,v>接口
HashMap集合的特点:
1、HashMap集合底层是哈希表:查询速度特别快
2、HashMap集合是一个无序的集合,存储元素和取出元素的顺序有可能不一致
java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合
LinkedHashMap的特点:
1、LinkedHashMap集合底层是哈希表+链表(保证迭代的顺序)
2、LinkedHashMap集合是一个有序的集合,存储元素和取出元素顺序是一致的

6.2 Map接口的常用方法

Map集合的方法:

public V put(K key, V value):把指定的键与指定的值添加到Map集合中

返回值:V
存储键值对的时候,key不重复,返回值V是null
存储键值对的时候,ke重复,会使用新的value替换map中重复的value,返回被替换的value值

public V remove(Object key):把指定的键所对应的键值对元素再Map集合中删除,返回被删除元素的值

返回值:V
key存在,V返回被删除的值
key不存在,V返回null

public V get(Object key)根据指定的键,在Map集中中获取对应的值

返回值:V
key存在,v返回被删除的值
key不存在,V返回null

boolean containsKey(Object key)判断集合中是否包含指定的键

包含返回true,不包含返回false

public class DemoMap {
    public static void main(String[] args) {
        demo01();
        demo02();
        demo03();
        demo04();
    }

    private static void demo04() {
        Map<String, Integer> map = new HashMap<>();
        map.put("小松狮",17);
        map.put("小锦鲤",18);
        map.put("小松狮1",17);
        boolean b1 = map.containsKey("小锦鲤");
        System.out.println(b1);//true
        boolean b2 = map.containsKey("小锦鲤3");
        System.out.println(b2);//false
    }

    private static void demo03() {
        Map<String, Integer> map = new HashMap<>();
        map.put("小松狮",17);
        map.put("小锦鲤",18);
        map.put("小松狮1",17);
        Integer v1 = map.get("小锦鲤");
        System.out.println(v1);//18
        Integer v2 = map.get("小松狮4");
        System.out.println(v2);//null
    }

    private static void demo02() {
        Map<String, Integer> map = new HashMap<>();
        map.put("小松狮",17);
        map.put("小锦鲤",18);
        map.put("小松狮1",17);
        System.out.println(map);//{小锦鲤=18, 小松狮=17, 小松狮1=17}
        Integer v1 = map.remove("小松狮");
        System.out.println(v1);//17
        Integer v2 = map.remove("小松狮3");
        System.out.println(v2);//null
        System.out.println(map);//{小锦鲤=18, 小松狮1=17}
    }

    private static void demo01() {
        Map<String, String> map = new HashMap<>();
        String v1 = map.put("小松狮", "小锦鲤");
        System.out.println(v1);//null
        String v2 = map.put("小松狮", "小锦鲤1");
        System.out.println(v2);//小锦鲤
        System.out.println(map);//{小松狮=小锦鲤1}
    }
}

Map集合的第一种遍历方式:通过键找值的方式

Map集合中的方法:Set keySet()
实现步骤:
1、使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
2、遍历set集合,获取Map集合中的每一个key
3、通过Map集合中的方法get(key),通过key找到value

public class Demo01KeySet {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("小松狮",17);
        map.put("小锦鲤",18);
        map.put("小松狮1",17);
        Set<String> set = map.keySet();
        Iterator<String> iterator = set.iterator();
        while (iterator.hasNext()){
            String key = iterator.next();
            Integer value = map.get(key);
            System.out.println(key + "-" + value);
        }
        System.out.println("=========");
        for(String key : map.keySet()){
            Integer value = map.get(key);
            System.out.println(key + "-" + value);
        }
    }
}

Map集合遍历的第二种方式:使用Entry对象遍历
Map.Entry<K,V>:在Map接口中有一个内部接口Entry
作用:当Map集合一创建,那么就会在Map集合中创建一个Entry对象,用来记录键与值
(键值对对象,键与值的映射关系)

Map集合中的方法:Set<Map.Entry<K,V>> entrySet()
实现步骤:
1、使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
2、遍历Set集合,获取每一个Entry对象
3、使用Entry对象中的方法getKey()和getValue()获取键与值

public class Demo02EntrySet {
    public static void main(String[] args) {
        Map<String, Integer> map = new HashMap<>();
        map.put("小松狮",17);
        map.put("小锦鲤",18);
        map.put("小松狮1",17);
        Set<Map.Entry<String, Integer>> set = map.entrySet();
        Iterator<Map.Entry<String, Integer>> it = set.iterator();
        while (it.hasNext()){
            Map.Entry<String, Integer> entry = it.next();
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key + "-" + value);
        }
        for(Map.Entry<String, Integer> entry: set){
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key + "-" + value);
        }
    }
}

6.3 HashMap存储自定义类型键值

HashMap存储自定义类型键值
Map集合保证key是唯一的:
作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一

public class Demo03HashMapSavePerson {
    public static void main(String[] args) {
        demo01();
        demo02();
    }
    /*
               HashMap存储自定义类型键值
               key:Person类型
                   Person类就必须重写hashCode方法和equals方法,以保证key唯一
               value:String类型
                   value可以重复
                */
    private static void demo02() {
        HashMap<Person, String> map = new HashMap<>();
        map.put(new Person("小松狮",18), "哈哈");
        map.put(new Person("小锦鲤",17), "嘿嘿");
        map.put(new Person("小松狮1",18), "嘎嘎");
        map.put(new Person("小松狮",18), "咕咕");
        Set<Map.Entry<Person, String>> set = map.entrySet();
        for (Map.Entry<Person, String> entry : set){
            Person key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key + "-" + value);
        }
    }

    /*
            HashMap存储自定义类型键值
            key:String类型
                String类重写hashCode方法和equals方法,可以保证key唯一
            value:Person类型
                value可以重复(同名同年龄的人视为同一人)
             */
    private static void demo01() {
        HashMap<String, Person> map = new HashMap<>();
        map.put("哈哈",new Person("小松狮",17));
        map.put("嘿嘿",new Person("小锦鲤",18));
        map.put("嘎嘎",new Person("小松狮1",19));
        map.put("哈哈",new Person("小松狮2",17));
        Set<String> set = map.keySet();
        for (String key : set){
            Person value = map.get(key);
            System.out.println(key + "-" + value);
        }
    }
}

java.util.LinkedHashMap<K,V> extends HashMap<k,v>
Map接口的哈希表和链接列表实现,具有可预知的迭代顺序
底层原理:
哈希表+链表(记录元素的顺序)

public class Demo04LinkedHashMap {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put("a","a");
        map.put("c","c");
        map.put("b","b");
        map.put("a","d");
        System.out.println(map);//key不允许重复,无序集合
        LinkedHashMap<String, String> linked = new LinkedHashMap<>();
        linked.put("a","a");
        linked.put("c","c");
        linked.put("b","b");
        linked.put("d","d");
        System.out.println(linked);//key不允许重复,有序集合
    }
}

6.4 Hashtable集合

java.util.Hashtable<K,V>集合 implements Map<K,V>接口
Hashtable:底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
HashMap:底层是一个哈希表,是一个线程不安全的集合,是多线程的集合,速度快
HashMap集合(之前学的所有集合):可以存储null值,null键
Hashtable集合,不能存储null值,null键
Hashtable和Vector集合一样,在jdk1.2版本之后被取代了
Hashtable的子类Properties依然活跃在历史舞台
Properties集合是一个唯一和IO流相结合的集合

public class Demo01HashTable {
    public static void main(String[] args) {
        HashMap<String, String> map = new HashMap<>();
        map.put(null, "a");
        map.put("b", null);
        map.put(null, null);
        System.out.println(map);//{null=null, b=null}
        Hashtable<String, String> table = new Hashtable<>();
        //table.put(null, "a");//.NullPointerException
        //table.put("b", null);//.NullPointerException
        //table.put(null, null);//.NullPointerException
    }
}

6.5 练习

计算一个字符串中每个字符出现的次数

import java.util.HashMap;
import java.util.Scanner;

/*
练习:计算一个字符串中每个字符出现次数
分析:
1、使用Scanner获取用户输入的字符串
2、创建Map集合,key是字符串中的字符,value是字符的个数
3、遍历字符串,获取每一个字符
4、使用获取到的字符,去Map集合判断key是否存在
key存在:通过字符(key),获取value(字符个数),value++,put(key,value)把新的value存储到Map集合中
key不存在:put(key,1)
5、遍历Map集合,输出结果
 */
public class Demo02MapTest {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入一个字符串:");
        String str = scanner.next();
        HashMap<Character, Integer> map = new HashMap<>();
        for (char c: str.toCharArray()){
            if (map.containsKey(c)){
                Integer value = map.get(c);
                value++;
                map.put(c, value);
            }else {
                map.put(c,1);
            }
        }
        for (Character key: map.keySet()){
            Integer value = map.get(key);
            System.out.println(key + "-" + value);
        }
    }
}

6.6 JDK9新特性

JDK9的新特性:
List接口,Set接口,Map接口:里边增加了一个静态方法of,可以给集合一次性添加多个元素
static List of(E… elements)
使用前提:
当集合中存储的元素的个数已经确定,不再改变时使用

注意:
1、of方法只适用于List接口,Set接口,Map接口,不适用于接口的实现类
2、of方法的返回值是一个不能改变的集合,集合不能再使用add,put方法添加元素,会抛出异常
3、Set接口和Map接口再调用of方法时,不能有重复元素,否则会抛出异常

public class Demo03 {
    public static void main(String[] args) {
        List<String> list = List.of("a", "b", "c", "a");
        System.out.println(list);//[a, b, c, a]
        //list.add("s");//错误!UnsupportedOperationException
        //Set<String> set = Set.of("a", "b", "a", "c", "d");
        //System.out.println(set);//错误!IllegalArgumentException,有重复元素
        Set<String> set = Set.of("a", "b",  "c", "d");
        System.out.println(set);//[d, c, b, a]
        Map<String, String> map = Map.of("小松狮", "17", "小锦鲤", "18");
        System.out.println(map);//{小松狮=17, 小锦鲤=18}
    }
}

第七节 Debug调试

Debug调试程序:
可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug
使用方式:
在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到那里)
右键,选择Debug执行程序
程序就会停留在添加的第一个断点处

执行程序:
F8:逐行执行程序
F7:进入到方法中
shift+F8:跳出方法
F9:跳到下一个断电,如果没有下一个断电,那么就结束程序
ctrl+F2:退出Debug模式,停止程序
Console:切换到控制台

第八节 斗地主案例

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

public class DouDiZhu {
    public static void main(String[] args) {
        //1、准备牌
        //创建一个Map集合,存储牌的索引和组装好的牌
        HashMap<Integer, String> poker = new HashMap<>();
        //创建一个List集合,存储牌的索引
        ArrayList<Integer> pokerIndex = new ArrayList<>();
        //定义两个集合,存储花色和牌的序号
        List<String> colors = List.of("♠","♥","♣","♦");
        List<String> numbers = List.of("2", "A", "K", "Q", "J", "10", "9", "8", "7", "6", "5", "4", "3");
        //把大王小王存储到集合中
        //定义一个牌的索引
        int index = 0;
        poker.put(index, "大王");
        pokerIndex.add(index);
        index++;
        poker.put(index, "小王");
        pokerIndex.add(index);
        index++;
        //循环嵌套遍历两个集合,组装52张牌,存储到集合中
        for (String number : numbers) {
            for (String color : colors) {
                poker.put(index, color + number);
                pokerIndex.add(index);
                index++;
            }
        }
        //System.out.println(poker);
        //System.out.println(pokerIndex);
        //2、洗牌
        Collections.shuffle(pokerIndex);
        //3、发牌
        //定义四个集合,存储玩家牌的索引和底牌的索引
        ArrayList<Integer> playerA = new ArrayList<>();
        ArrayList<Integer> playerB = new ArrayList<>();
        ArrayList<Integer> playerC = new ArrayList<>();
        ArrayList<Integer> diPai = new ArrayList<>();
        //遍历存储索引的List集合,获取每一个牌的索引
        for (int i = 0; i < pokerIndex.size(); i++) {
            Integer in = pokerIndex.get(i);
            //先判断底牌
            if (i >= 51){
                diPai.add(in);
            }else if (i % 3 == 0){
                playerA.add(in);
            }else if (i % 3 == 1){
                playerB.add(in);
            }
            else if (i % 3 == 2){
                playerC.add(in);
            }
        }
        //4、排序
        Collections.sort(playerA);
        Collections.sort(playerB);
        Collections.sort(playerC);
        Collections.sort(diPai);
        /*
        5、看牌
        定义一个看牌的方法,提高代码的复用性
        参数:
        String name:玩家名称
        HashMap<Integer, String> poker:存储牌的poker集合
        ArrayList<Integer> list:存储玩家和底牌的List集合
        查表法:
        遍历玩家或者底牌集合,获取牌的索引
        使用牌的索引,去Map集合中,找到对应的牌
         */
        lookPoker("赌神", poker, playerA);
        lookPoker("赌侠", poker, playerB);
        lookPoker("赌圣", poker, playerC);
        lookPoker("底牌", poker, diPai);
    }
    public static void lookPoker(String name, HashMap<Integer, String> poker, ArrayList<Integer> list){
        //输出玩家名称,不换行
        System.out.print(name + ":");
        //遍历玩家或底牌集合,获取牌的索引
        for (Integer key : list){
            String value = poker.get(key);
            System.out.print(value + " ");
        }
        System.out.println();
    }
}
这篇关于JAVA-集合的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!