Java学习(数据结构(栈,队列,数组,链表,红黑树),List接口,Set接口,Collections集合工具类,可变参数,Map接口,JDK9优化的of方法,Debug追踪,斗地主案例)

2022/1/8  1/9

1.数据结构:栈(先进后出)
入口和出口在同一侧
入栈5又称之为压栈
出栈又称之为弹栈
eg.入栈顺序为123,出栈顺序为321

2.数据结构:队列(先进先出)
入口和出口在集合的两侧
eg.进入队列123,出队列也是123

3.数据结构:数组
查询快:数组的地址是连续的,我们通过数组的首地址可以找到数组,通过数组的索引可以快速查找某一个元素。
增删慢:数组的长度是固定的,我们想要增加、删除一个元素,必须创建一个新数组,把源数组的数据复制过来。
eg.删除数组中索引是3的元素
        1.必须创建一个新的数组,长度是源数组的长度-1
        2.把源数组的其他元素复制到新数组中
        3.把新数组的地址赋值给变量
        4.源数组会在内存中被销毁(垃圾回收)

4.数据结构:链表
查询慢:链表中的地址不是连续的,每次查询元素,都必须从头开始。
增删快:链表结构增加或删除一个元素,对链表整体结构没有影响。
链表中的每一个元素也称之为一个节点
双向链表中一个节点包含了一个数据域(存储数组),两个指针域(存储地址)

自己的地址           数据        下一个节点的地址   

单向链表中一个节点包含一个数据域(存储数据)一个指针域(存储地址)

数据         下一个节点的地址

单向链表:链表中只有一条链子,只能找到其后继节点。
双向链表:链表中有两条链子,能够找通过链子找到其前驱节点和后继节点。

5.数据结构:红黑树
二叉树:分支不能超过两个
排序树/查找树:在二叉树的基础上,元素是有大小顺序的(左子数小,右子数大)
平衡二叉树:树种所有节点的左子树和右子树深度相差不超过1
平衡树是二叉查找树和堆合并构成的新的数据结构,所以和二叉查找树一样满足左子树<根节点<右子树。
红黑树:特点:趋近于平衡树,查询的速度非常的快,查询叶子节点最大次数和最小次数不能超过两倍
               约束:1.节点可以是红色或者黑色的
                          2.根节点是黑色的
                          3.叶子节点(空节点)也是黑色的
                          4.每个红色的节点的子节点都是黑色的
                          5.任何一个节点到其每一个叶子节点的所有路径上黑色节点数相同

6.List集合

package ln.javatest.day12.demo01;
/*
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:索引越界异常,集合会报
    ArrayIndexOutOfBoundsException:数组索引越界异常
    StringIndexOutOfBoundsException:字符串索引越界异常
*/

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

public class Demo01List {
    public static void main(String[] args) {
        //创建一个list集合对象,多态
        List<String> list = new ArrayList<>();
        //使用add方法添加元素
        list.add("a");
        list.add("b");
        System.out.println(list); //[a,b]  不是地址,重写了toString方法
        //在1号索引位置添加3
        list.add(1,"3");
        System.out.println(list); //[a, 3, b]
        //移除2号索引位置的元素
        String s = list.remove(2);
        System.out.println("被移除的元素是:"+ s); //被移除的元素是:b
        System.out.println(list); //[a, 3]
        //把1号索引位置的元素替换为A
        String s1 = list.set(1,"A");
        System.out.println("被替换的元素是:"+ s1);
        System.out.println(list); //
        //list集合遍历有3种方式
        //使用普通for循环遍历
        for (int i = 0; i < list.size(); i++) {
            String s2 = list.get(i);
            System.out.println(s2);
        }
        //使用迭代器
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String s2 = it.next();
            System.out.println(s2);
        }
        //使用增强for
        for (String s2 : list) {
            System.out.println(s2);
        }

    }
}

7.ArrayList集合:(List接口的大小可变数组的实现)
她的底层数据结构是一个数组(数组的特点:查询快,增删慢)
这个实现不是同步的,多线程,速度快。
建议:查询的时候可以大量使用ArrayList集合,但是在增删的时候不建议使用。

 

8.LinkedList集合:(List接口的连接列表实现)
它的底层是一个链表(链表的特点:查询慢,增删快)
这个实现不是同步的,多线程,速度快。
建议:查询的时候不建议使用,但是在增删的时候可以大量使用LinkedList集合。

package ln.javatest.day12.demo01;
/*
java.util.LinkedList集合 implements List接口
LinkedList集合的特点:
    1.底层是一个链表结构:查询慢,增删快
    2.里面包含了大量操作首尾元素的方法
    注意:使用LinkedList集合特有的方法,不能使用多态(多态的弊端是,看不到子类特有方法)

    public void  addFirst(E e):将指定元素插入此列表的开头
    public void  addLast(E e):将指定元素添加到此列表的结尾
    public void  push(E e):将指定元素推入此列表所表示的堆栈的第一个

    public E  getFirst():返回此列表的第一个元素
    public E  getLast():返回此列表的最后一个元素

    public E removeFirst():溢出并返回此列表的第一个元素
    public E removeLast():移除并返回此列表的最后一个元素
    public E pop():从此列表所表示的堆栈处弹出弟一个元素

    public boolean isEmpty():如果列表中不包含元素,则返回true
*/

import java.util.LinkedList;

public class Demo02LinkedList {
    public static void main(String[] args) {
        show01();
        show02();
        show03();
    }

    /*public void  addFirst(E e):将指定元素插入此列表的开头
    public void  addLast(E e):将指定元素添加到此列表的结尾
    public void  push(E e):将指定元素推入此列表所表示的堆栈的第一个*/
    private static void show01() {
        //创建LinkedList集合对象
        LinkedList<String> linked = new LinkedList<>();
        //使用add方法往集合中添加元素
        linked.add("a");
        linked.add("b");
        System.out.println(linked); //[a, b]
        //addFirst
        linked.addFirst("最前");
        System.out.println(linked); //[最前, a, b]
        //push
        linked.push("推入的");
        System.out.println(linked); //[推入的, 最前, a, b]
        //addLast
        linked.addLast("最后");
        System.out.println(linked); //[推入的, 最前, a, b, 最后]

    }

    /*public E  getFirst():返回此列表的第一个元素
   public E  getLast():返回此列表的最后一个元素*/
    private static void show02() {

        //创建LinkedList集合对象
        LinkedList<String> linked1 = new LinkedList<>();
        //使用add方法往集合中添加元素
        linked1.add("a");
        linked1.add("b");
        System.out.println(linked1); //[a, b]
        //linked1.clear(); 清空了下面取不到会报错
        if(!linked1.isEmpty()){
            String first = linked1.getFirst();
            String last = linked1.getLast();
            System.out.println(first); //a
            System.out.println(last);  //b
        }
    }

    /*public E removeFirst():溢出并返回此列表的第一个元素
    public E removeLast():移除并返回此列表的最后一个元素
    public E pop():从此列表所表示的堆栈处弹出弟一个元素*/
    private static void show03() {
        //创建LinkedList集合对象
        LinkedList<String> linked2 = new LinkedList<>();
        //使用add方法往集合中添加元素
        linked2.add("a");
        linked2.add("b");
        System.out.println(linked2); //[a, b]
        String first1 = linked2.removeFirst();
        System.out.println(first1); //a
        System.out.println(linked2); //[b]
        String last1 = linked2.removeLast();
        System.out.println(last1); //b
        System.out.println(linked2); //[]
        //pop相当于First
        /*String first2 = linked2.pop();
        System.out.println(first2);
        System.out.println(linked2);*/
    }
}

9.Vector集合:类可以实现可增长的对象数组
和ArrayList底层一样
但它是单线程的,速度比较慢,不是多线程的所以被ArrayList取代
addElement(E ob);  将指定的组件添加到此向量的末尾,并将其大小增加1

10.set接口:一个不包含重复元素的Collection

package ln.javatest.day12.demo01;
/*
java.util.Set接口 extends Collection接口
set接口的特点:
    1.不允许存储重复的元素
    2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
java.util.HashSet集合  implements Set接口
    1.不允许存储重复的元素
    2.没有索引,没有带索引的方法,也不能使用普通的for循环遍历
    3.是一个无序的集合,存储元素和取出元素的顺序有可能不一致
    4.底层是一个哈希表结构(查询速度非常的快)
*/

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

public class Demo01Set {
    public static void main(String[] args) {
        //多态写法
        Set<Integer> set = new HashSet<>();
        //使用add添加
        set.add(1);
        set.add(2);
        set.add(3);
        set.add(1); //前面有重复1 所以只存储一个1
        //使用迭代器遍历
        Iterator<Integer> it = set.iterator();
        while(it.hasNext()){
            Integer n = it.next();
            System.out.println(n);
        }
        //使用增强for
        for(Integer i : set){
            System.out.println(i);
        }

    }
}

11.哈希值

package ln.javatest.day12.demo01;

public class Person {
    //重写HashCode方法

    @Override
    public int hashCode() {
        return 1;
    }
}
package ln.javatest.day12.demo01;
/*
哈希值:是一个十进制的整数,有系统随机给出(就是对象的地址值,是个逻辑地址,是模拟出来得到的地址,不是数据实际存储的物理地址)
在Object类有一个方法,可以获取对象的哈希值
int hashCode():返回该对象的哈希码值
hashCode方法的源码:
    public native int hashCode();
    native :代表该方法调用的是本地操作系统的方法
*/

public class Demo01HashCode {
    public static void main(String[] args) {
        //Person类继承了Object类,所以可以使用Object类的hasCode方法
        Person p1 = new Person();
        int h1 = p1.hashCode();
        System.out.println(h1);  //1

        Person p2 = new Person();
        int h2 = p1.hashCode();
        System.out.println(h2);  //1
        //对象的地址值用的是hashCode,只不过是用十六进制表示

        //物理地址不相等
        System.out.println(p1==p2);//false

        /*
        String类的哈希值
            String类重写了Object类的hashCode方法
        */
        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1.hashCode()); //96354
        System.out.println(s2.hashCode()); //96354
    }
}

12.哈希表
HashSet集合存储数据的结构:哈希表
jdk1.8版本之前:哈希表 = 数组 +链表
jdk1.8版本之后:哈希表 = 数组 +链表
                            哈希表 = 数组 + 红黑树(提高查询的速度)
数据结构把元素进行分组,相同哈希值元素是一组,链表/红黑树把相同哈希值的元素连接到一起
哈希表的特点:速度快

存储数据到集合中,先计算元素的哈希值
两个元素不同,但是哈希值相同,哈希冲突
把哈希值放入数组中,相同元素都放在哈希值下面,通过数组索引进行查询,查询快

jdk1.8之后,如果链表中相同元素超过8位,那么就转成红黑树进行连接
红黑树(根   黑色,叶子节点   黑色 ,中间节点   红色)
用红黑树:提高查询的速度

13.Set集合存储数据不重复的原理
前提:重写的元素必须重写hashCode方法和equals方法
Set集合在调用add方法的时候,add方法会调用元素的hashCode方法和equals方法,判断元素是否重复。
重复的话就不存储,不重复的话,就把元素也存储到集合中,用链表链起来

14.HashSet存储自定义类型元素

package ln.javatest.day12.demo01;

import java.util.Objects;

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

    @Override
    public String toString() {
        return "Person1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

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

    @Override
    public int hashCode() {
        return Objects.hash(name, 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;
    }

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

    public Person1() {
    }
}
package ln.javatest.day12.demo01;
/*
HashSet存储自定义类型元素
set集合保证元素唯一:
    存储的元素,必须重写hashCode方法和equals方法
    Getter/Setter方法里可以帮我们重写hashCode和equals方法
要求:
同名年龄的的人,视为同一人,只能存储一次
*/

import java.util.HashSet;

public class Demo01HashSetSavePerson {
    public static void main(String[] args) {
        //创建HashSet集合存储Person
        HashSet<Person1> set = new HashSet<>();
        Person1 p1 = new Person1("王嘉尔", 20);
        Person1 p2 = new Person1("王嘉尔", 20);
        //没有重写hashCode和equals方法,上面两个都会存入集合
        //重写了所以上面两行一样的只存储一个
        Person1 p3 = new Person1("王嘉尔", 22);
        set.add(p1);
        set.add(p2);
        set.add(p3);
        System.out.println(set);

    }
}

15.LinkedHashSet集合
继承HashSet接口,能实现Set接口
它的特点:
        底层是一个哈希表(数组+链表/红黑树)+链表:多了一条链表,用来记录元素的存储顺序,保证元素有序。
和HashSet方法一样,它和HashSet不一样在于它可以保证元素输入输出顺序一致。

16.可变参数

package ln.javatest.day12.demo01;
/*
可变参数:是JDk1.5之后出现的新特性
使用前提:
    当方法的参数列表数据类型已经确定,但是参数的个数不确定,就可以使用可变参数
使用格式:定义方法时使用
    修饰符 返回值类型 方法名(数据类型...变量名){}
可变参数的原理:
    可变参数底层就是一个数组,根据传递参数个数不同,会创建不同长度的数组
    来存储这些参数传递的参数个数,可以是0个(不传递),1,2...多个
*/

public class Demo01VarArgs {
    public static void main(String[] args) {
        int i = add(10,20);
        System.out.println(i);
    }
    /*
    可变参数的注意事项:
        1.一个方法的参数列表,只能有一个可变参数
        错误写法:private static int add(int...i,String...s){}
        2.如果方法的参数有多个,那么可变参数必须写在参数列表的末尾
        错误写法:private static int add(int...arr,String s,double d){}
        正确写法:private static int add(String s,double d,int...arr){}
    */

    private static int add(int...arr) {
        System.out.println(arr); //输出时一个地址,因为底层是一个数组
        System.out.println(arr.length); //2
        int sum = 0;
        for (int i : arr) {
            sum += i;
        }
        return sum;
    }

}

17.Collections集合工具类的方法

package ln.javatest.day12.demo01;
//因为要用到Collects集合工具类中的方法sort实现类的排序,那么要指定根据什么来排序
//所以需要这个类实现Comparable接口,重写Comparable接口中的compareTo方法
public class Person2 implements Comparable<Person2>{  //这里因为是对Person2进行排序,所以泛型要写Person2
    private String name;
    private int age;

    //重写排序的规则
    @Override
    public int compareTo(Person2 o) {
        //return 0; //认为元素都是相同的
        //自定义比较的规则,比较两个人的年龄(this,参数Person2)
        return this.getAge() - o.getAge(); //年龄升序排序
    }

    @Override
    public String toString() {
        return "Person2{" +
                "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;
    }

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

    public Person2() {
    }
}
package ln.javatest.day12.demo01;

public class Student {
    private String name;
    private int 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;
    }

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

    public Student() {
    }

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
package ln.javatest.day12.demo01;
/*
java.util.Collections是集合工具类,用来对集合进行操作。部分方法如下:
    public static <T> boolean addAll(Collection<T> c,T...elements):往集合中添加一些元素。
    public static void shuffle<list<?> list) :打乱集合顺序。
    public static <T> void sort(list<T> list):将集合中元素按照默认规则排序。(升序)
    public static <T> void sort(list<T> list,Comparator<? super T>):将集合中元素按照指定规则排序。(传一个集合,一个比较器,按照比较器里重写的compare方法来弄)
注意:
    Comparator和Comparable的区别:
        Comparable:自己this和别人参数比较,自己需要实现Comparable接口,重写比较的规则compareTo方法
        Comparator:相当于找一个第三方的裁判,比较两个

注意:
    sort方法使用前提:
    被排序的集合里边存储的元素,必须实现Comparable,重写接口中的方法compareTo
Comparable接口的排序规则:
    this-参数(升序)
    参数-this(降序)
*/

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

public class Demo01Collections {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        //一次性往集合中添加多个元素,相当于多个add方法
        Collections.addAll(list,"b","a","c","e","f");
        System.out.println(list); //[b, a, c, e, f]
        Collections.shuffle(list);
        System.out.println(list); //[c, a, f, e, b]
        //sort方法值用在List(有序)集合中不用在Set集合(无序)中
        Collections.sort(list);
        System.out.println(list); //[a, b, c, e, f]
        ArrayList<Person2> p = new ArrayList<>();
        //Collections.addAll(Person2,"王嘉尔",10,"熊丰",20);
        p.add(new Person2("王嘉尔",20));
        p.add(new Person2("熊丰",20));
        //上面这种情况下,用sort进行排序,有两个参数没有指定根据哪个排序,所以需要重写compareTo方法
        Collections.sort(p);
        System.out.println(p); //[Person2{name='王嘉尔', age=20}, Person2{name='熊丰', age=20}]
        ArrayList<Integer> list1 = new ArrayList<>();
        //一次性往集合中添加多个元素,相当于多个add方法
        Collections.addAll(list1,1,5,9,3,6);
        System.out.println(list1);  //[1, 5, 9, 3, 6]
        Collections.sort(list1, new Comparator<Integer>() {
            //重写比较的规则
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2; //升序
            }
        });
        System.out.println(list1); //[1, 3, 5, 6, 9]
        ArrayList<Student> p1 = new ArrayList<>();
        p1.add(new Student("王",27));
        p1.add(new Student("熊",29));
        Collections.sort(p1, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                //按照年龄排序
                int result = o1.getAge() - o2.getAge();
                //如果两个人年龄相同,再使用姓名的第一个字比较
                if(result == 0){
                    result = o1.getName().charAt(0) - o2.getName().charAt(0);
                }
                return result;
            }
        });
        System.out.println(p1); //[Student{name='王', age=27}, Student{name='熊', age=29}]

    }
}

18.Map集合(接口)
 

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

java.util.HashMap<K,V>集合 implements Map<K,v>接口
HashSet集合new的就是HashMap,但是只用了其中的K,这里的K不能重复,所以HashSet中的不允许存储重复的数据;
HashMap的特点:
    1.HashMap底层也是一个哈希表(数组+链表/红黑树),和HashSet一样:查询的速度非常快
    2.这里HashMap还是一个无序的集合;
    3.是个多线程,不同步;
java.util.LinkedHashMap<k,v>集合 extends HashMap<k,v>集合
LinkedHashMap的特点:
    1.底层是哈希表+链表,双重链表,另一个存储顺序
    2.LinkedHashMap集合是一个有序的集合
*/

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

public class Demo01Map {
    public static void main(String[] args) {
        //Map接口中的常用方法
        show01();
        show02();
        show03();
        show04();
    }

    /*
    public V put(K key,V value):把指定的键与指定的值添加到Map集合中
        返回值:v
            存储键值对的时候,key不重复,返回值v是null
            存储键值对的时候,key重复,会使用新的value替换map中重复的value,返回被替换的value值
    */
    private static void show01() {
        //创建Map集合对象,多态
        Map<String,String> map = new HashMap<>();
        String v1 = map.put("王嘉尔","11");
        System.out.println("v1:" + v1);  //v1:null
        String v2 = map.put("王嘉尔","22"); //v2:11
        System.out.println("v2:" + v2);
        System.out.println(map); //{王嘉尔=22}
    }

    /*
    public V remove (Object key):把指定的键,所对应的键值对元素,在Map集合中删除,返回被删除元素的值
        返回值:v
            key存在,v返回被删除的值
            key不存在,v返回null
    */
    private static void show02() {
        //c创建Map集合对象
        Map<String,Integer> map1 = new HashMap<>();
        map1.put("王嘉尔",20);
        map1.put("熊丰",18);
        System.out.println(map1); //{熊丰=18, 王嘉尔=20}
        Integer n = map1.remove("王嘉尔");
        System.out.println(n);  //20
        System.out.println(map1); //{熊丰=18}
        Integer n1 = map1.remove("易烊千玺");
        System.out.println(n1); //null
        System.out.println(map1); //{熊丰=18}
    }

    /*
    public V get(Object key):根据指定的键,获取Map集合中获取对应的值
    返回值:v
        key存在,返回对应的value值
        key不存在,返回null
    */
    private static void show03() {
        Map<String,Integer> map2 = new HashMap<>();
        map2.put("王嘉尔",20);
        map2.put("熊丰",18);
        Integer v1 = map2.get("王嘉尔");
        System.out.println(v1);//20
        Integer v2 = map2.get("ni");
        System.out.println(v2);//null

    }

    /*
    boolean containsKey(Object key):判断集合中是否包含指定的键。
    包含返回true,不包含返回false
    */
    private static void show04() {
        Map<String,Integer> map3 = new HashMap<>();
        map3.put("王嘉尔",20);
        map3.put("熊丰",18);
        boolean b1 = map3.containsKey("王嘉尔");
        System.out.println(b1); //true
        boolean b2 = map3.containsKey("ni");
        System.out.println(b2); //true
    }

}
     

19.Map集合遍历键找值方式
1.

package ln.javatest.day12.demo02;
/*
Map集合的第一种遍历方式:通过键找值的方式
Map集合中的方法:
    Set<K> keySet() 返回此映射中包含的键的Set视图。
实现步骤:
    1.使用Map集合中的方法KeySet(),把Map集合所有的key取出来,存储到一个Set集合中
    2.遍历Set集合,获取Map集合中的每一个key
    3.通过Map集合中的方法get(key),通过key找到value

*/

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

public class Demo02KeySet {
    public static void main(String[] args) {
        //创建Map集合对象
        Map<String,Integer> map = new HashMap<>();
        map.put("王嘉尔",20);
        map.put("易烊千玺",27);
        map.put("王一博",29);
        //1.使用Map集合中的方法keySet(),把Map集合所有的key取出来,存储到一个Set集合中
        Set<String> set = map.keySet();
        //2.遍历set集合,获取Map集合中的每一个key值
        //使用迭代器
        Iterator<String> it = set.iterator();
        while(it.hasNext()){
            String s = it.next();
            //3.通过Map集合中的get(key),通过key找到value
            Integer value = map.get(s);
            System.out.println(s+","+value);
        }
        //使用增强for
        for (String s : /*用set或者后面那个都行,这两相等*/map.keySet()) {
            //3.通过Map集合中的get(key),通过key找到value
            Integer value = map.get(s);
            System.out.println(s+","+value);
        }


    }
}

2.Entry键值对对象
Map.Entry<K,V>:在Map接口中有一个内部接口Entry
作用:当Map集合一创建,那么就会在Map集合中创建一个Entry对象用来记录仪键与值(键值对对象、键与值的映射关系)eg:结婚证

package ln.javatest.day12.demo02;
/*
Map集合中的方法:
    Set<Map.Entry<K,v>> entrySet() 返回此映射中包含的映射关系的Set视图
实现步骤:
    1.使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
    2.遍历Set集合,获取每一个Entry对象
    3.使用Entry对象中的方法getKey()和getValue()获取键与值
*/

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

public class Demo03EntrySet {
    public static void main(String[] args) {
        //创建Map集合对象
        Map<String,Integer> map = new HashMap<>();
        map.put("王嘉尔",20);
        map.put("易烊千玺",27);
        map.put("王一博",29);
        //使用迭代器
        //1.使用Map集合中的方法entrySet(),把Map集合中多个Entry对象取出来,存储到一个Set集合中
        Set<Map.Entry<String,Integer>> set = map.entrySet();
        //  2.遍历Set集合,获取每一个Entry对象
        Iterator<Map.Entry<String, Integer>> it = set.iterator();
        while(it.hasNext()){
            Map.Entry<String, Integer> entry = it.next();
            //3.使用Entry对象中的方法getKey()和getValue()获取键与值
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key+","+value);
        }
        for (Map.Entry<String, Integer> entry : set) {
            //3.使用Entry对象中的方法getKey()和getValue()获取键与值
            String key = entry.getKey();
            Integer value = entry.getValue();
            System.out.println(key+","+value);
        }
    }
}

20.HashMap存储自定义类型键值

package ln.javatest.day12.demo02;

public class Person {
    private String name;
    private int 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;
    }

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

    public Person() {
    }
}
package ln.javatest.day12.demo02;

import java.util.Objects;

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

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

    @Override
    public int hashCode() {
        return Objects.hash(name, 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;
    }

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

    public Person1() {
    }
}
package ln.javatest.day12.demo02;
/*
HashMap存储自定义类型键值
Map集合保证key是唯一的:
    作为key的元素,必须重写hashCode方法和equals方法,以保证key唯一
*/
import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class Demo01HashMapSavePerson {
    public static void main(String[] args) {
        show01();
        show02();
    }
    /*
        HashMap存储自定义类型的键值
        key:Person1类型
            Person1类就必须重写hashCode和equals方法,以保证key唯一
        value:String (可以重复)
        */
    private static void show02() {
        //创建HashMap集合
        HashMap<Person1, String> map2 = new HashMap<>();
        //往集合中添加元素
        map2.put(new Person1("王嘉尔", 20), "北京");
        map2.put(new Person1("易烊千玺", 23), "上海");
        map2.put(new Person1("王嘉尔", 20), "深圳");
        map2.put(new Person1("熊丰", 20), "北京");
        //使用entrySet(取出多个对象)加增强for遍历Map1集合
        Set<Map.Entry<Person1, String>> set1 = map2.entrySet();
        for (Map.Entry<Person1, String> entry : set1) {
            Person1 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 show01() {
        //创建HashMap集合
        HashMap<String, Person> map1 = new HashMap<>();
        //往集合中添加元素
        map1.put("北京", new Person("王嘉尔", 20));
        map1.put("上海", new Person("易烊千玺", 23));
        map1.put("深圳", new Person("王嘉尔", 20));
        map1.put("北京", new Person("熊丰", 20));
        //使用keySet(返回key值)加增强for遍历Map集合
        Set<String> set = map1.keySet();
        for (String key : set) {
            Person value = map1.get(key);
            System.out.println(key + "," + value);
        }



    }
}

21.LinkedHashMap集合继承HashMap集合
底层原理:哈希表+链表(记录元素的顺序)
LinkedHashMap是个有序的集合

22.Hashtable集合

package ln.javatest.day12.demo02;
/*
java.util.Hashtable<K,V>集合 implements Map<K,v>接口
Hashtable:底层也是一个哈希表,是一个线程安全的集合,是单线程集合,速度慢
HashMap:底层也是一歌哈希表,是一个线程不安全的集合,是多线程集合,速度快

HashMap集合(和之前学的所有集合):都可以存储null值,null键
Hashtable集合:不能存储null值,null键

Hashtable和Vector集合一样,被(HashMap,ArrayList)取代了
Hashtable的子类Properties依然活跃在历史舞台
Properties集合是唯一和IO流相结合的集合
*/

import java.util.HashMap;
import java.util.Hashtable;

public class Demo02HashTable {
    public static void main(String[] args) {
        HashMap<String,String> map = new HashMap<>();
        map.put(null,null);
        System.out.println(map);
        Hashtable<String,String> table = new Hashtable<>();
        //出错table(null,null);
    }
}

23.练习

package ln.javatest.day12.demo02;
/*
练习:
    计算一个字符串中每个字符出现次数
分析:
    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集合,输出结果
*/

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

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

24.of方法

package ln.javatest.day12.demo02;
/*
JDK9的新特性:
    List接口,Set接口,Map接口:里面增加了一个静态的方法of,可以给集合一次性添加多个元素
    Static <E> List<E> of{ }
    使用前提:
        当集合中存储的元素的个数已经确定了,不在改变时使用
注意:
    1.of方法只适用于List,Set,Map这三个接口
    2.of方法的返回值是一个不能改变的集合,不能再使用add和put,会抛出异常
    3.Set接口和Map接口在调用of方法的时候,不能有重复的元素,否则会抛出异常
*/

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Demo01JDK9 {
    public static void main(String[] args) {
        List<String> list = List.of("a", "b", "a");
        //有重复,出错Set<String> set = Set.of("a", "b", "a");
        Set<String> set = Set.of("a", "b", "c");
        //key有重复,错误Map<String,Integer> map = Map.of("a",1, "b",,3, "a",2);
        Map<String,Integer> map = Map.of("a",1, "b",3, "c",2);
        //list集合中可以有重复的元素,Set和Map不行
        System.out.println(list);
        System.out.println(set);
        System.out.println(map);
        //错误list.add("d");
        //错误set.add("d");
        //错误map.add("d",6);

    }
}

25.Debug调试程序
可以让代码逐行执行,查看代码执行的过程,调试程序中出现的bug
使用方式:
        在行号的右边,鼠标左键单击,添加断点(每个方法的第一行,哪里有bug添加到哪里)
        右键,选择Debug执行程序
        程序就会停留在添加的第一个断点处
执行程序:
        f8:逐行执行程序
        f7:进入到方法中
        shift+f8:跳出方法
        f9:跳到下一个断点,如果没有下一个断点,那么就结束程序
        ctrl+f2:退出debug模式,停止程序
        Console:切换到控制台

26.练习

package ln.javatest.day12.demo02;
/*
斗地主综合案例:有序版本
1.准备牌
2.洗牌
3.发牌
4.排序
5.看牌
*/

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++;
            }
        }
        //2.洗牌
        //使用Collections中的方法shuffle(List)
        Collections.shuffle(pokerIndex);
        //3.发牌
        //定义4个集合,存储玩家牌的索引,和底牌的索引
        ArrayList<Integer> play01 = new ArrayList<>();
        ArrayList<Integer> play02 = new ArrayList<>();
        ArrayList<Integer> play03 = 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){
                //给玩家1发牌
                play01.add(in);
            }else if(i % 3 == 1){
                //给玩家2发牌
                play02.add(in);
            }else if(i % 3 == 2){
                //给玩家3发牌
                play03.add(in);
            }
        }
        //4.排序
        //使用Collections中的方法sort(List)
        Collections.sort(play01);
        Collections.sort(play02);
        Collections.sort(play03);
        Collections.sort(diPai);
        //5.看牌
        
        lookpoker("王嘉尔",poker,play01);
        lookpoker("王嘉尔",poker,play02);
        lookpoker("王嘉尔",poker,play03);
        lookpoker("王嘉尔",poker,diPai);
    }

    /*
        定义一个看牌的方法,提高代码的复用性
        参数:
            String name:玩家名称
            HashMap<Integer,String> poker :存储牌的poker集合
            ArrayList<Integer> list:存储玩家和底牌的List集合
        查表法:
            遍历玩家或者底牌集合,获取牌的索引
            使用牌的索引,去Map集合中,找到对应的牌
        */
    private static void lookpoker(String name,HashMap<Integer,String> poker,ArrayList<Integer> list) {
        //输出玩家名称,不换行
        System.out.print(name +":");
        //遍历玩家或者底牌集合,获取牌的索引
        for (Integer key : list) {
            //使用牌的索引,去Map集合中,找到相应的牌
            String value = poker.get(key);
            System.out.print(value + " ");
        }
        //打印完每一个玩家的牌换行
        System.out.println();

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值