E

229 阅读31分钟

第一章.集合框架(单列集合)

 1.集合:分为两大类
 2.分类:
   单列集合:集合中的元素单独保存
           list.add("张三");
           list.add("李四");
   双列集合:集合中的元素都是成对出现(键值对 key value形式)
           map.put("涛哥","柳岩")
 1.概述:容器
 2.作用:存储数据
 3.特点:
   a.只能存储引用数据类型
   b.长度可变
   c.集合有很多强大的方法来直接操作元素

image-20220305093747392

第二章.Collection接口

 1.概述:单列集合的顶级接口
 2.特点:
   a.元素有序
   b.元素可重复
   c.无索引(没有通过索引操作元素的方法)
 3.使用:
   Collection<E> 集合名 = new 实现类对象<E>()
   a.<E>:泛型  -> a.泛型必须是引用数据类型   b.泛型是为了明确,集合中元素的数据类型
                 c.如果要是不指定,默认泛型为Object类型
   b.比如:Collection<String> 集合名 = new 实现类对象<String>()
   c.注意:等号右边的泛型可以不写
 4.方法:
   boolean add(E e) : 将给定的元素添加到当前集合中(我们一般调add时,不用boolean接收,因为add一定会成功)
   boolean addAll(Collection<? extends E> c) :将另一个集合元素添加到当前集合中 (集合合并)
   void clear():清除集合中所有的元素
   boolean contains(Object o)  :判断当前集合中是否包含指定的元素
   boolean isEmpty() : 判断当前集合中是否有元素->判断集合是否为空
   boolean remove(Object o):将指定的元素从集合中删除
   int size() :返回集合中的元素数。
   Object[] toArray(): 把集合中的元素,存储到数组中
 public class Test01 {
     public static void main(String[] args) {
         //创建Collection集合
         Collection<String> collection = new ArrayList<String>();
         //boolean add(E e) : 将给定的元素添加到当前集合中(我们一般调add时,不用boolean接收,因为add一定会成功)
         collection.add("张三");
         collection.add("李四");
         collection.add("王五");
         collection.add("赵六");
         collection.add("田七");
         collection.add("猪八");
         collection.add("猪八");
         System.out.println(collection);
         /*
            boolean addAll(Collection<? extends E> c) :将另一个集合元素添加到当前集合中 (集合合并)
            参数:Collection接口类型
          */
         Collection<String> collection1 = new ArrayList<String>();
         collection1.add("刘备");
         collection1.add("关羽");
         collection1.add("张飞");
         collection1.add("赵云");
         collection1.add("黄忠");
         collection1.add("马超");
 ​
         collection.addAll(collection1);
         System.out.println(collection);
 ​
 ​
         Collection<String> collection2 = new ArrayList<>();
         collection2.add("释迦牟尼佛");
         collection2.add("斗战胜佛");
         collection2.add("旃檀功德佛");
         collection2.add("阿弥陀佛");
         collection2.add("南无大圣舍利尊王佛");
         //void clear():清除集合中所有的元素
 ​
         /*collection2.clear();
         System.out.println(collection2);*/
 ​
         //boolean contains(Object o)  :判断当前集合中是否包含指定的元素
         boolean result01 = collection2.contains("斗战胜佛");
         System.out.println("result01 = " + result01);
         //boolean isEmpty() : 判断当前集合中是否有元素->判断集合是否为空
         System.out.println(collection2.isEmpty());
         //boolean remove(Object o):将指定的元素从集合中删除
         /*
         boolean result02 = collection2.remove("南无大圣舍利尊王佛");
         System.out.println("result02 = " + result02);
         System.out.println(collection2);
         */
         //int size() :返回集合中的元素数。
         System.out.println(collection2.size());
         //Object[] toArray()  : 把集合中的元素,存储到数组中
         Object[] array = collection2.toArray();
         for (int i = 0; i < array.length; i++) {
             System.out.println(array[i]);
         }
     }
 }

第三章.迭代器

1.迭代器基本使用

 1.概述:迭代器是一个接口-> Iterator
 2.获取:
   Collection中的方法:Iterator<E> iterator() -> 凡是Collection以及实现类都可以用此方法获取迭代器对象
 3.方法:
   boolean hasNext() -> 判断是否有下一个元素
   E next() -> 获取下一个元素
 public class Test01 {
     public static void main(String[] args) {
         ArrayList<String> list = new ArrayList<>();
         list.add("孙悟空");
         list.add("二郎神");
         list.add("哮天犬");
         list.add("姜子牙");
         //获取迭代器对象
         Iterator<String> iterator = list.iterator();
         while(iterator.hasNext()){
             System.out.println(iterator.next());
         }
     }
 }
 ​

经验值:使用迭代器时尽量不要连续调用多次next()方法获取元素

 public class Test01 {
 public static void main(String[] args) {
   ArrayList<String> list = new ArrayList<>();
   list.add("孙悟空");
   list.add("二郎神");
   list.add("哮天犬");
   //获取迭代器对象
   Iterator<String> iterator = list.iterator();
   while(iterator.hasNext()){
       System.out.println(iterator.next());
       //System.out.println(iterator.next());
   }
 }
 }

image-20220305104803656

2.迭代器迭代原理

image-20220305105150728

3.迭代器底层原理

 Iterator<String> iterator = list.iterator();
 等号左边是Iterator接口,必然会接收一个实现类,实现类是哪个实现类呢?

image-20220305111644873

1.注意:

Iterator指向ArrayList内部类Itr,这种情况,仅仅局限于迭代ArrayList集合

2.如果迭代HashSet集合,Iterator指向的实现类就不是Itr,那么是谁呢?

image-20220305112603940

4.并发修改异常

 1.需求:定义集合,存储"孙悟空","唐僧","猪八戒","沙和尚",遍历集合,在遍历的过程中,如果获取出来的是猪八戒,就直接在集合中添加"白龙马"
 public class Test02 {
     public static void main(String[] args) {
         /*
           1.需求:定义集合,存储"孙悟空","唐僧","猪八戒","沙和尚",
           遍历集合,在遍历的过程中,如果获取出来的是猪八戒,就直接在集合中添加"白龙马"
          */
 ​
         ArrayList<String> list = new ArrayList<>();
         list.add("孙悟空");
         list.add("唐僧");
         list.add("猪八戒");
         list.add("沙和尚");
 ​
         Iterator<String> iterator = list.iterator();
         while(iterator.hasNext()){
             String element = iterator.next();
             if ("猪八戒".equals(element)){
                 list.add("白龙马");
             }
         }
 ​
         System.out.println(list);
 ​
     }
 }
 Exception in thread "main" java.util.ConcurrentModificationException--> 并发修改异常
     at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
     at java.util.ArrayList$Itr.next(ArrayList.java:859)
     at com.atguigu.b_iterator.Test02.main(Test02.java:21)
     
 结论:使用迭代器的过程中,不能随便改变集合长度
 问题1.为什么上面的代码会出现并发修改异常呢?
 =======================================
 Iterator<String> iterator = list.iterator();
 public Iterator<E> iterator() {
     return new Itr();
 }
 ​
 private class Itr implements Iterator<E> {
     
         /*
          modCount:实际操作次数
          expectedModCount:预期操作次数
         */
         int expectedModCount = modCount;
     
         @SuppressWarnings("unchecked")
         public E next() {
             checkForComodification();
         }
     
        final void checkForComodification() {
            /*
              如果实际操作次数不等于预期操作次数
              直接抛出"并发修改异常"
            */
             if (modCount != expectedModCount)
                 throw new ConcurrentModificationException();
        }
 }
 ​
 结论:当实际操作次数不等于预期操作次数直接抛出"并发修改异常"
问题2:我们做什么操作了,导致了modCount和expectedModCount不相等了呢? -> 调用了ArrayList中的add方法
==========================================================================================
list.add("白龙马");
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
}
private void ensureCapacityInternal(int minCapacity) {
    ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private void ensureExplicitCapacity(int minCapacity) {
    modCount++;
}
最总结论:为甚出现并发修改异常
       当调用add时,只给modCount++了,然后expectedModCount并没有被重新赋值,此时再调用next方法,next方法底层直接做了判断
       如果modCount和expectedModCount不相等,就直接出现"并发修改异常"

扩展:ListIterator迭代器(了解)

 public class Test02 {
 public static void main(String[] args) {
   /*
     1.需求:定义集合,存储"孙悟空","唐僧","猪八戒","沙和尚",
     遍历集合,在遍历的过程中,如果获取出来的是猪八戒,就直接在集合中添加"白龙马"
    */
 ​
   ArrayList<String> list = new ArrayList<>();
   list.add("孙悟空");
   list.add("唐僧");
   list.add("猪八戒");
   list.add("沙和尚");
 ​
  /* Iterator<String> iterator = list.iterator();
   while(iterator.hasNext()){
       String element = iterator.next();
       if ("猪八戒".equals(element)){
           list.add("白龙马");
       }
   }*/
 ​
   ListIterator<String> iterator = list.listIterator();
   while(iterator.hasNext()){
       String element = iterator.next();
       if ("猪八戒".equals(element)){
           iterator.add("白龙马");
       }
   }
   System.out.println(list);
 ​
 }
 }
 ​

第四章.数据结构

1.栈

 1.特点:
   先进后出
 2.好比:手枪压子弹

2.队列

 1.特点:先进先出
 2.好比:排队

3.数组

 1.特点:
   查询快(有索引)
   增删慢(定长)
 2.如果想往数组中添加一个元素,首先要创建一个新数组,将老数组的元素复制到新数组中,然后在最后添加新的元素

4.链表

 1.特点:
   查询慢
   增删快
 2.分类:
   单向链表
   双向链表

4.1单向链表

 1.特点:
   一个节点分成2部分
    第一部分:数据域-> 存数据
    第二部分:指针域-> 下一个元素的地址
        
 2.前面的节点记录后面的节点地址
   但是后面的节点地址不记录前面的节点地址
        
 3.如果集合底层是单向链表,无法保证元素有序

image-20220305142224972

4.2双向链表

 1.特点:
   一个节点分3部分
   第一部分:上一个节点地址
   第二部分:数据域
   第三部分:下一个节点地址
       
 2.一个节点,既记录上一个节点地址,也记录下一个节点地址
    前面记录后面的节点,后面记录前面的节点
     
 3.如果集合底层数据结构是双向链表,能保证元素有序

image-20220305143042682

第五章.List接口

 1.概述:
   List接口是Collection接口的子接口
 2.特点:
   a.元素有序
   b.元素可重复
   c.有索引
 3.数据结构:不同的实现类数据结构不同

第六章.List集合下的实现类

1.ArrayList集合

 1.概述:ArrayList是List接口的实现类
 2.特点:
   a.元素有序
   b.元素可重复
   c.有索引
 3.数据结构:
   数组
 4.使用:
   ArrayList<泛型> 集合名 = new ArrayList<>()
 5.常用方法:
   boolean add(E e)  -> 将元素添加到集合中->尾部(add方法一定能添加成功的,所以我们不用boolean接收返回值)
   void add(int index, E element) ->在指定索引位置上添加元素
   boolean remove(Object o) ->删除指定的元素,删除成功为true,失败为false
   E remove(int index) -> 删除指定索引位置上的元素,返回的是被删除的那个元素
   E set(int index, E element) -> 将指定索引位置上的元素,修改成后面的element元素
   E get(int index) -> 根据索引获取元素
   int size()  -> 获取集合元素个数

1.1.ArrayList集合使用

 public class Demo01ArrayList {
     public static void main(String[] args) {
         //创建ArrayList集合
         ArrayList<String> list = new ArrayList<String>();
         //boolean add(E e)  -> 将元素添加到集合中->尾部(add方法一定能添加成功的,所以我们不用boolean接收返回值)
         list.add("玉皇大帝");
         list.add("王母娘娘");
         list.add("涛哥");
         list.add("如来佛祖");
         System.out.println(list);
         //void add(int index, E element) ->在指定索引位置上添加元素
         list.add(0, "翠儿");
         System.out.println(list);
         //boolean remove(Object o) ->删除指定的元素,删除成功为true,失败为false
         /*boolean result01 = list.remove("涛哥");
         System.out.println(result01);
         System.out.println(list);*/
         //E remove(int index) -> 删除指定索引位置上的元素,返回的是被删除的那个元素
         /*System.out.println(list.remove(0));
         System.out.println(list);*/
         //E set(int index, E element) -> 将指定索引位置上的元素,修改成后面的element元素
         String element1 = list.set(0, "太上老君");
         System.out.println(element1);
         System.out.println(list);
         //E get(int index) -> 根据索引获取元素
         System.out.println(list.get(0));
         //int size()  -> 获取集合元素个数
 ​
         System.out.println(list.size());
     }
 }
 ​
 //遍历ArrayList集合
 public class Demo02ArrayList {
     public static void main(String[] args) {
         ArrayList<String> list = new ArrayList<>();
         list.add("岳不群");
         list.add("林平之");
         list.add("东方不败");
         list.add("任我行");
         list.add("尹志平");
         //迭代器
         Iterator<String> iterator = list.iterator();
         while(iterator.hasNext()){
             System.out.println(iterator.next());
         }
 ​
         System.out.println("======================");
 ​
         for (int i = 0; i < list.size(); i++) {
             System.out.println(list.get(i));
         }
 ​
         System.out.println("======================");
         /*
           遍历快捷键
           集合名.fori
          */
 ​
         for (int i = 0; i < list.size(); i++) {
             System.out.println(list.get(i));
         }
         
     }
 }

经验值:

 public class Demo03ArrayList {
 public static void main(String[] args) {
     ArrayList<Integer> list = new ArrayList<>();
     list.add(2);
     /*
       集合只有一个元素
       如果直接调用remove传递2
       2默认类型为int型
       所以会直接调用删除指定索引位置上的元素的那个remove
 ​
       解决:
         将2变成Integer类型
      */
     //list.remove(2);
     list.remove(new Integer(2));
     System.out.println(list);
 }
 }
 ​

1.2.底层源码分析(扩展)

 1.ArrayList构造:
   a.ArrayList()   构造一个初始容量为 10 的空列表(数组)
                   并不是一new ArrayList底层就会马上创建一个容量为10的空列表
                   而是在第一次add的时候ArrayList底层才会马上创建一个容量为10的空列表
       
   b.ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。
       
       
 2.数组是定长的,集合长度可变,那么ArrayList底层是数组,为什么还要说ArrayList长度可变呢?怎么变的长度?
    elementData = Arrays.copyOf(elementData, newCapacity);
 ​
 3.如果超出了数组的初始化容量,ArrayList底层自动扩容,怎么扩的?
    elementData = Arrays.copyOf(elementData, newCapacity); 
 ​
 4.扩容多少倍?  1.5倍
   int newCapacity = oldCapacity + (oldCapacity >> 1);
 ArrayList<String> list = new ArrayList<>();
 =========================================================================
 private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {}
 transient Object[] elementData;-> ArrayList底层数组
 ​
 public ArrayList() {
     this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
 }
 ​
 ==========================================================================
 在第一次add的时候ArrayList底层才会马上创建一个容量为10的空列表
 list.add("abc");
 ​
 public boolean add(E e) {//e  ->  abc
     ensureCapacityInternal(size + 1);  // Increments modCount!!
 }
 ​
 private void ensureCapacityInternal(int minCapacity --> 1) {
     // ensureExplicitCapacity(10);
     ensureExplicitCapacity(calculateCapacity(elementData-> 数组 , minCapacity  -> 1));
 }
 ​
 private static int calculateCapacity(Object[] elementData -> 数组, int minCapacity -> 1) {
     if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
         return Math.max(DEFAULT_CAPACITY ->10, minCapacity-->1);  //返回10
     }
     return minCapacity;
 }
 ​
 private void ensureExplicitCapacity(int minCapacity-->10) {
     modCount++;
 ​
     // overflow-conscious code
     if (minCapacity - elementData.length > 0)
         grow(minCapacity-->10);
 }
 ​
 private void grow(int minCapacity-->10) {
     // overflow-conscious code
     int oldCapacity = elementData.length;//0
     int newCapacity = oldCapacity + (oldCapacity >> 1);//   0+(0/2)    0
     if (newCapacity - minCapacity < 0)
         newCapacity = minCapacity;//  10
     if (newCapacity - MAX_ARRAY_SIZE > 0)
         newCapacity = hugeCapacity(minCapacity);
     // minCapacity is usually close to size, so this is a win:
     
     /*
       elementData = Arrays.copyOf(elementData,10)-> 数组扩容
     */
     elementData = Arrays.copyOf(elementData, newCapacity);
 }
 ​
 =============================================================
 ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。
     
 ArrayList<String> list = new ArrayList<>(10);    
     
 public ArrayList(int initialCapacity-->10) {
     if (initialCapacity > 0) {
         this.elementData = new Object[initialCapacity];
     } else if (initialCapacity == 0) {
         this.elementData = EMPTY_ELEMENTDATA;
     } else {
         throw new IllegalArgumentException("Illegal Capacity: "+
                                            initialCapacity);
     }
 }

第七章.LinkedList集合

 1.概述:LinkedList 是List的实现类
 2.特点:
   a.元素有序
   b.有索引
   c.元素可重复
 3.底层数据结构:
   双向链表
 4.常用方法->很多直接操作首尾元素的方法
     - 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 Demo05LinkedList {
     public static void main(String[] args) {
         LinkedList<String> list = new LinkedList<>();
         list.add("柳岩");
         list.add("金莲");
         list.add("松下");
         list.add("三上");
         list.add("大桥");
         list.add("涛哥");
         //- public void addFirst(E e):将指定元素插入此列表的开头。
         list.addFirst("大郎");
         System.out.println(list);
         //- public void addLast(E e):将指定元素添加到此列表的结尾。
         list.addLast("二郎");
         System.out.println(list);
         //- public E getFirst():返回此列表的第一个元素。
         System.out.println(list.getFirst());
         //- public E getLast():返回此列表的最后一个元素。
         System.out.println(list.getLast());
         //- public E removeFirst():移除并返回此列表的第一个元素。
         System.out.println(list.removeFirst());
         System.out.println(list);
         //- public E removeLast():移除并返回此列表的最后一个元素。
         list.removeLast();
         System.out.println(list);
     }
 }
 ​
 public class Demo06LinkedList {
     public static void main(String[] args) {
         LinkedList<String> list = new LinkedList<>();
         list.add("柳岩");
         list.add("金莲");
         list.add("松下");
         list.add("三上");
         list.add("大桥");
         list.add("涛哥");
 ​
         //迭代器
         Iterator<String> iterator = list.iterator();
         while(iterator.hasNext()){
             System.out.println(iterator.next());
         }
 ​
         //普通for
         for (int i = 0; i < list.size(); i++) {
             System.out.println(list.get(i));
         }
     }
 }
 ​
 - public E pop():从此列表所表示的堆栈处弹出一个元素。
 - public void push(E e):将元素推入此列表所表示的堆栈
 public class Demo07LinkedList {
     public static void main(String[] args) {
         LinkedList<String> list = new LinkedList<>();
         list.add("柳岩");
         list.add("金莲");
         list.add("松下");
         list.add("三上");
         list.add("大桥");
         list.add("涛哥");
         System.out.println(list);
         //- public E pop():从此列表所表示的堆栈处弹出一个元素。
         list.pop();
         System.out.println(list);
         //- public void push(E e):将元素推入此列表所表示的堆栈
         list.push("张三");
         System.out.println(list);
     }
 }

第八章.LinkedList集合

1.LinkedList集合

 1.概述:LinkedList是List的实现类
 2.特点:
   元素有序
   元素可重复
   有索引
 3.数据结构:链表(双向链表)
 4.特有方法:
 - 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 Demo01LinkedList {
     public static void main(String[] args) {
         //创建LinkedList集合对象
         LinkedList<String> list = new LinkedList<>();
         list.add("张无忌");
         list.add("张三丰");
         list.add("张翠山");
         list.add("赵敏");
         list.add("周芷若");
 ​
         //- public void addFirst(E e):将指定元素插入此列表的开头。
         list.addFirst("玄冥二老");
         System.out.println(list);
         //- public void addLast(E e):将指定元素添加到此列表的结尾。
         list.addLast("灭绝师太");
         System.out.println(list);
 ​
         //- public E pop():从此列表所表示的堆栈处弹出一个元素。
         //list.pop();
         //System.out.println(list);
         //- public void push(E e):将元素推入此列表所表示的堆栈。
         list.push("金毛狮王");
         System.out.println(list);
 ​
         System.out.println("===========================");
         //普通for遍历
         for (int i = 0; i < list.size(); i++) {
             System.out.println(list.get(i));
         }
         //迭代器
         Iterator<String> iterator = list.iterator();
         while(iterator.hasNext()){
             System.out.println(iterator.next());
         }
     }
 }

1.1 LinkedList底层成员解释说明

 1.LinkedList底层成员
   transient int size = 0;  元素个数
   transient Node<E> first; 第一个节点对象
   transient Node<E> last;  最后一个节点对象
   
 2.Node代表的是结点对象
    private static class Node<E> {
         E item;//节点上的元素
         Node<E> next;//记录着下一个节点地址
         Node<E> prev;//记录着上一个节点地址
 ​
         Node(Node<E> prev, E element, Node<E> next) {
             this.item = element;
             this.next = next;
             this.prev = prev;
         }
     }

1.2 LinkedList中add方法源码分析

 LinkedList<String> list = new LinkedList<>();
 list.add("a");
 list.add("b");    
 ​
 void linkLast(E e) {
         final Node<E> l = last;
         final Node<E> newNode = new Node<>(l, e, null);
         last = newNode;
         if (l == null)
             first = newNode;
         else
             l.next = newNode;
         size++;
         modCount++;
 }

image-20220307092239790

1.3.LinkedList中get方法源码分析

 public E get(int index) {
     checkElementIndex(index);
     return node(index).item;
 } 
 ​
 Node<E> node(int index) {
     // assert isElementIndex(index);
 ​
     if (index < (size >> 1)) {
         Node<E> x = first;
         for (int i = 0; i < index; i++)
             x = x.next;
         return x;
     } else {
         Node<E> x = last;
         for (int i = size - 1; i > index; i--)
             x = x.prev;
         return x;
     }
 }
 index < (size >> 1)采用二分思想,先将index与长度size的一半比较,如果index<size/2,就只从位置0往后遍历到位置index处,而如果index>size/2,就只从位置size往前遍历到位置index处。这样可以减少一部分不必要的遍历

第九章.Collections集合工具类

 1.概述:Collections,是集合工具类
 2.特点:
   a.构造私有
   b.方法都是静态的
 3.使用:
   类名直接调用
 4.常用方法:
   static <T> boolean addAll(Collection<? super T> c, T... elements)->批量将元素存到集合中
   static void shuffle(List<?> list) -> 将集合中的元素顺序打乱 
   static  <T> void sort(List<T> list) ->将集合中的元素按照默认规则排序->ASCII
   static <T> void sort(List<T> list, Comparator<? super T> c)->将集合中的元素按照指定规则排序 
 public class Test01 {
     public static void main(String[] args) {
         ArrayList<String> list = new ArrayList<>();
         //static <T> boolean addAll(Collection<? super T> c, T... elements)->批量将元素存到集合
         Collections.addAll(list,"樱桃小丸子","铁臂阿童木","蜡笔小新","飞天小女警");
         System.out.println(list);
         //static void shuffle(List<?> list) -> 将集合中的元素顺序打乱
         Collections.shuffle(list);
         System.out.println(list);
 ​
         //static  <T> void sort(List<T> list) ->将集合中的元素按照默认规则排序->ASCII
         ArrayList<String> list1 = new ArrayList<>();
         list1.add("Ba");
         list1.add("Ac");
         list1.add("Cd");
         list1.add("Db");
         Collections.sort(list1);
         System.out.println(list1);
     }
 }
 ​
  1.static <T> void sort(List<T> list, Comparator<? super T> c)->将集合中的元素按照指定规则排序
      
  2.Comparator:比较器,接口    
  3.Comparator接口中的方法:
    int compare(T o1, T o2)  
        o1-o2-> 升序
        o2-o1-> 降序
 public class Person {
     private String name;
     private int age;
 ​
     public Person() {
     }
 ​
     public Person(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 String toString() {
         return "Person{" +
                 "name='" + name + ''' +
                 ", age=" + age +
                 '}';
     }
 }
 ​
 public class Test02 {
     public static void main(String[] args) {
         ArrayList<Person> list = new ArrayList<>();
         list.add(new Person("柳岩",36));
         list.add(new Person("涛哥",18));
         list.add(new Person("翠儿",45));
 ​
         Collections.sort(list, new Comparator<Person>() {
             @Override
             public int compare(Person o1, Person o2) {
                 return o2.getAge()-o1.getAge();
             }
         });
 ​
         System.out.println(list);
     }
 }

比较器:Comparable接口

 方法:
 public int compareTo(T o);
 比较:
 this-o -> 升序
 o-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;
 }
 ​
 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 String toString() {
   return "Person{" +
           "name='" + name + ''' +
           ", age=" + age +
           '}';
 }
 ​
 @Override
 public int compareTo(Person o) {
   return o.age-this.age;
 }
 }
 public class Test02 {
 public static void main(String[] args) {
   ArrayList<Person> list = new ArrayList<>();
   list.add(new Person("柳岩",36));
   list.add(new Person("涛哥",18));
   list.add(new Person("翠儿",45));
 ​
  /* Collections.sort(list, new Comparator<Person>() {
       @Override
       public int compare(Person o1, Person o2) {
           return o2.getAge()-o1.getAge();
       }
   });*/
 ​
  Collections.sort(list);
 ​
   System.out.println(list);
 ​
 ​
 }
 }

第十章.增强for

1.增强for的介绍以及基本使用

 1.作用:主要是遍历集合和数组的
 2.格式:
   for(元素的类型 变量名:集合或者数组名){
       变量名接收的就是集合或者数组中的每一个元素
   }
 public class Test01 {
     public static void main(String[] args) {
        // method01();
         method02();
 ​
     }
 ​
     private static void method02() {
         int[] arr = {1,2,3,4,5,6};
         for (int i : arr) {
             System.out.println(i);
         }
     }
 ​
     public static void method01() {
         ArrayList<String> list = new ArrayList<>();
         list.add("樱桃小丸子");
         list.add("百变小樱魔术卡");
         list.add("飞天小女警");
         list.add("巴拉啦小魔仙");
 ​
         //普通for
         for (int i = 0; i < list.size(); i++) {
             System.out.println(list.get(i));
         }
         System.out.println("=======================");
 ​
         //迭代器
         Iterator<String> iterator = list.iterator();
         while(iterator.hasNext()){
             System.out.println(iterator.next());
         }
         System.out.println("===========================");
 ​
         //增强for->快捷键->集合名或者数组名.for
         for (String s : list) {
             System.out.println(s);
         }
     }
 }
 ​
 快捷键:集合名或者数组名.for

2.使用增强for的注意事项

 1.注意:
   如果使用增强for,遍历集合,过程中也不能随意删除添加元素,会抛出并发修改异常
 2.原因:
   在使用增强for遍历集合时,底层原理是迭代器
   在使用增强for遍历数组时,底层原理是普通for

image-20220307104530131

image-20220307104640212

idea自带反编译功能:

image-20220307111249532

第十一章.泛型

1.为什么要使用泛型

 1.从使用的角度:统一元素的数据类型,防止类型转换异常
 2.从定义的角度:使用起来很方便,可以传递任意类型,传递什么类型,我们就操作什么类型的数据,通用

image-20220307141813149

2.泛型的定义

2.1含有泛型的类

 1.格式:
   public class 类名<E>{
   
   }
 2.什么时候确定类型:
   创建对象的时候
 public class ArrayList_Myself<E> {
     public void add(E e){
         System.out.println(e);
     }
 }
 ​
 public class Test01 {
     public static void main(String[] args) {
         ArrayList_Myself<Integer> list = new ArrayList_Myself<>();
         list.add(1);
     }
 }

2.2含有泛型的方法

 1.格式:
   修饰符 <E> 返回值类型 方法名(E e){}
 2.什么时候确定类型
   调用的时候确定类型
 public class ArrayList_MySelf {
     public <E> void add(E e){
         System.out.println(e);
     }
 }
 public class Test01 {
     public static void main(String[] args) {
         ArrayList_MySelf list = new ArrayList_MySelf();
         list.add("1");
         list.add(1);
     }
 }

2.3含有泛型的接口

 1.定义:
   public interface 接口名<E>{}
 2.什么时候确定类型:
   a.在实现类的时候就确定类型  ->  Scanner
   b.在实现类的时候还是不确定类型,在创建实现类对象时确定类型  -> ArrayList
 public interface Iterator_Myself<E> {
     public E next(E e);
 }
 public class Scanner_Myself implements Iterator_Myself<String>{
 ​
     @Override
     public String next(String s) {
         return s;
     }
 }
 public class Test01 {
     public static void main(String[] args) {
         Scanner_Myself scanner_myself = new Scanner_Myself();
         String result = scanner_myself.next("shuru");
         System.out.println("result = " + result);
     }
 }
 public interface List_Myself <E>{
     public void add(E e);
 }
 ​
 public class ArrayList_Myself<E> implements List_Myself<E>{
     @Override
     public void add(E e) {
         System.out.println(e);
     }
 }
 ​
 public class Test {
     public static void main(String[] args) {
         ArrayList_Myself<String> list = new ArrayList_Myself<>();
         list.add("hahaha");
     }
 }
 ​

image-20220307144307121

3.泛型的高级使用

3.1 泛型通配符 ?

 1.什么时候用泛型通配符:参数位置当不知道接收什么类型时->一般用在集合方面
 2.用在什么位置上:一般用在参数位置
 public class Test01 {
     public static void main(String[] args) {
         ArrayList<String> list1 = new ArrayList<>();
         list1.add("郭嘉");
         list1.add("诸葛亮");
         list1.add("庞统");
         list1.add("陆逊");
 ​
         ArrayList<Integer> list2 = new ArrayList<>();
         list2.add(1);
         list2.add(2);
         list2.add(3);
 ​
         method(list1);
         method(list2);
     }
 ​
     public static void method(ArrayList<?> list){
         for (Object o : list) {
             System.out.println(o);
         }
     }
 }
 ​

3.2 泛型的上限下限

 泛型通配符的高级使用--受限泛型
 ​
 1.上限:
   a.格式: 类型名称<? extends 类> 对象名
   b.意义: ?只能接受extends后面的本类以及子类
 2.下限:
   a.格式: 类型名称<? super 类> 对象名
   b.意义: ?只能接受super后的本类以及父类
 /*
   Integer->Number->Object
   String->Object
  */
 public class Test02 {
         public static void main(String[] args) {
             Collection<Integer> list1 = new ArrayList<>();
             Collection<String> list2 = new ArrayList<>();
             Collection<Number> list3 = new ArrayList<>();
             Collection<Object> list4 = new ArrayList<>();
 ​
             getElement1(list1);
             //getElement1(list2);报错
             getElement1(list3);
             //getElement1(list4);报错
 ​
             System.out.println("==================");
 ​
             //getElement2(list1);//报错
             //getElement2(list2);//报错
             getElement2(list3);
             getElement2(list4);
         }
 ​
         //上限  ?只能接受extends后面的本类以及子类
         public static void getElement1(Collection<? extends Number> collection){
 ​
         }
 ​
         //下限 ?只能接受super后的本类以及父类
 ​
         public static void getElement2(Collection<? super Number> collection){
 ​
         }
 }
 ​

第十二章.斗地主案例

5.1 案例介绍

按照斗地主的规则,完成洗牌发牌的动作。 具体规则:

使用54张牌打乱顺序,三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。

5.2 案例分析

  • 准备牌:

    牌可以设计为一个ArrayList<String>每个字符串为一张牌。 每张牌由花色数字两部分组成,我们可以使用花色集合与数字集合嵌套迭代完成每张牌的组装。 牌由Collections类的shuffle方法进行随机排序。

  • 发牌

    将每个人以及底牌设计为ArrayList<String>,将最后3张牌直接存放于底牌,剩余牌通过对3取模依次发牌。

  • 看牌

    直接打印每个集合。

image-20220307112928833

5.3 代码实现

 实现步骤:
   准备牌组合牌:
    1.定义两个集合,分别存储牌号(pokerNumber)和花色(pokerColor)
    2.定义一个集合,用于存储拼接好的牌面(poker)
    3.遍历pokerNumber和pokerColor,进行牌号和花色的拼接,存储到poker集合中,别忘记大小王
    
   洗牌:
    4.利用Collections中的shuffle,对poker中的元素进行打乱
   
   发牌:
    5.定义4个集合,分别表示玩家1(player1),玩家2(player2),玩家3(player3),底牌(dipai)
    6.遍历poker,利用索引去%3判断
      如果index%3==0,将牌存储到player1中
      如果index%3==1,将牌存储到player2中
      如果index%3==2,将牌存储到player3中
      如果index>=51,直接放到dipai集合中
        
   看牌:
      7.遍历四个集合:player1,player2,player3,dipai       
 public class Poker {
     public static void main(String[] args) {
         //准备牌组合牌:
         //1.定义两个集合,分别存储牌号(pokerNumber)和花色(pokerColor)
         ArrayList<String> pokerNumber = new ArrayList<>();
         for (int i = 2; i <= 10; i++) {
             pokerNumber.add(i+"");
         }
         pokerNumber.add("J");
         pokerNumber.add("Q");
         pokerNumber.add("K");
         pokerNumber.add("A");
 ​
         ArrayList<String> pokerColor = new ArrayList<>();
         pokerColor.add("♠");
         pokerColor.add("♥");
         pokerColor.add("♣");
         pokerColor.add("♦");
         //2.定义一个集合,用于存储拼接好的牌面(poker)
         ArrayList<String> poker = new ArrayList<>();
         //3.遍历pokerNumber和pokerColor,进行牌号和花色的拼接,存储到poker集合中,别忘记大小王
         for (String color : pokerColor) {
             for (String number : pokerNumber) {
                 String s = color+number;
                 poker.add(s);
             }
         }
         poker.add("大🤡");
         poker.add("小🤡");
 ​
         //洗牌:
         //4.利用Collections中的shuffle,对poker中的元素进行打乱
         Collections.shuffle(poker);
 ​
         //发牌:
         //5.定义4个集合,分别表示玩家1(player1),玩家2(player2),玩家3(player3),底牌(dipai)
         ArrayList<String> player1 = new ArrayList<>();
         ArrayList<String> player2 = new ArrayList<>();
         ArrayList<String> player3 = new ArrayList<>();
         ArrayList<String> dipai = new ArrayList<>();
         //6.遍历poker,利用索引去%3判断
         for (int i = 0; i < poker.size(); i++) {
             String pNum = poker.get(i);
             //如果index>=51,直接放到dipai集合中
             if (i>=51){
                 dipai.add(pNum);
             }else{
 ​
                 //如果index%3==0,将牌存储到player1中
                 if (i%3==0){
                     player1.add(pNum);
                 }else if (i%3==1){
                 //如果index%3==1,将牌存储到player2中
                     player2.add(pNum);
                 }else{
                 //如果index%3==2,将牌存储到player3中
                     player3.add(pNum);
                 }
             }
 ​
         }
 ​
         //看牌:
         //7.遍历四个集合:player1,player2,player3,dipai
         System.out.println("涛哥:"+player1);
         System.out.println("翠儿:"+player2);
         System.out.println("静静:"+player3);
         System.out.println("底牌:"+dipai);
     }
 }
 ​
 public class Poker_Array {
     public static void main(String[] args) {
         //准备牌组合牌:
         //1.定义两个数组,分别存储牌号(pokerNumber)和花色(pokerColor)
         String[] pokerNumber = "2-3-4-5-6-7-8-9-10-J-Q-K-A".split("-");
         String[] pokerColor = "♠-♥-♣-♦".split("-");
         //2.定义一个集合,用于存储拼接好的牌面(poker)
         ArrayList<String> poker = new ArrayList<>();
         //3.遍历pokerNumber和pokerColor,进行牌号和花色的拼接,存储到poker集合中,别忘记大小王
         for (String color : pokerColor) {
             for (String number : pokerNumber) {
                 String s = color+number;
                 poker.add(s);
             }
         }
         poker.add("大🤡");
         poker.add("小🤡");
 ​
         //洗牌:
         //4.利用Collections中的shuffle,对poker中的元素进行打乱
         Collections.shuffle(poker);
 ​
         //发牌:
         //5.定义4个集合,分别表示玩家1(player1),玩家2(player2),玩家3(player3),底牌(dipai)
         ArrayList<String> player1 = new ArrayList<>();
         ArrayList<String> player2 = new ArrayList<>();
         ArrayList<String> player3 = new ArrayList<>();
         ArrayList<String> dipai = new ArrayList<>();
         //6.遍历poker,利用索引去%3判断
         for (int i = 0; i < poker.size(); i++) {
             String pNum = poker.get(i);
             //如果index>=51,直接放到dipai集合中
             if (i>=51){
                 dipai.add(pNum);
             }else{
 ​
                 //如果index%3==0,将牌存储到player1中
                 if (i%3==0){
                     player1.add(pNum);
                 }else if (i%3==1){
                 //如果index%3==1,将牌存储到player2中
                     player2.add(pNum);
                 }else{
                 //如果index%3==2,将牌存储到player3中
                     player3.add(pNum);
                 }
             }
         }
 ​
         //看牌:
         //7.遍历四个集合:player1,player2,player3,dipai
         System.out.println("涛哥:"+player1);
         System.out.println("翠儿:"+player2);
         System.out.println("静静:"+player3);
         System.out.println("底牌:"+dipai);
     }
 }

第十三章.红黑树(了解)

 1.结论:加入红黑树的目的-> 查询快

image-20220307155013205

第十四章.Set集合

1.Set集合介绍

 1.概述:Set接口  继承自 Collection接口
       Set接口中的方法,并没有对Collection接口进行扩充
       底层都是依靠Map实现

image-20220307161932446

2.HashSet集合的介绍和使用

 1.概述:HashSet 实现  Set接口
 2.特点:
   元素无序
   元素唯一(如果元素一样,后面的会把前面的覆盖掉)
   没有索引(迭代器遍历,增强for遍历)
 3.数据结构:哈希表
   jdk8之前:哈希表 = 数组+链表
   jdk8之后:哈希表 = 数组+链表+红黑树
   加入红黑树的目的:查询快,提高效率
 4.方法:
   和Collection一样
 public class Demo01Set {
     public static void main(String[] args) {
         HashSet<String> set = new HashSet<>();
         set.add("abc");
         set.add("abc");
         set.add("通话");
         set.add("重地");
         set.add("吕布");
         set.add("貂蝉");
         System.out.println(set);
 ​
         //迭代器
         Iterator<String> iterator = set.iterator();
         while(iterator.hasNext()){
             System.out.println(iterator.next());
         }
 ​
         System.out.println("======================");
 ​
         //增强for
         for (String s : set) {
             System.out.println(s);
         }
     }
 }
 ​

3.LinkedHashSet的介绍以及使用

 1.概述:LinkedHashSet extends HashSet
 2.特点:
   元素有序
   元素唯一(如果元素一样,后面的会把前面的覆盖掉)
   没有索引(迭代器遍历,增强for遍历)
 3.数据结构:哈希表+链表
 4.方法:
   和HashSet一样
 public class Demo01Set {
     public static void main(String[] args) {
         LinkedHashSet<String> set = new LinkedHashSet<>();
         set.add("abc");
         set.add("abc");
         set.add("通话");
         set.add("重地");
         set.add("吕布");
         set.add("貂蝉");
         System.out.println(set);
 ​
         //迭代器
         Iterator<String> iterator = set.iterator();
         while(iterator.hasNext()){
             System.out.println(iterator.next());
         }
 ​
         System.out.println("======================");
 ​
         //增强for
         for (String s : set) {
             System.out.println(s);
         }
     }
 }

4.哈希值

 1.概述:计算机计算出来的十进制数,可以理解为对象的地址值
 2.获取哈希值:
   调用Object类中的hashCode()方法
 3.结论:
   a.如果想要获取对象内容的哈希值,重写hashCode方法
   b.内容一样,算出来的哈希值一定一样
   c.内容不一样,算出来的哈希值也有可能一样(哈希碰撞,哈希冲突)
 public class Test01 {
     public static void main(String[] args) {
         Person p1 = new Person("柳岩", 36);
         Person p2 = new Person("柳岩", 36);
         System.out.println(p1.toString());
         System.out.println(p2.toString());
         System.out.println(p1.hashCode());
         System.out.println(Integer.toHexString(p1.hashCode()));
         System.out.println(p2.hashCode());
         System.out.println(Integer.toHexString(p2.hashCode()));
 ​
         System.out.println("=====================");
 ​
         String s = "abc";
         String s1 = "abc";
 ​
         System.out.println(s.hashCode());
         System.out.println(s1.hashCode());
 ​
         String s2 = "通话";
         String s3 = "重地";
         System.out.println(s2.hashCode());//1179395
         System.out.println(s3.hashCode());//1179395
     }
 }

5.字符串的哈希值时如何算出来的

 String s = "abc";
 System.out.println(s.hashCode());//96354
 char[] value = {'a','b','c'}
 ​
 public int hashCode() {
     int h = hash;
     if (h == 0 && value.length > 0) {
         char val[] = value;
 ​
         for (int i = 0; i < value.length; i++) {
             h = 31 * h + val[i];
         }
         hash = h;
     }
     return h;
 }
 ​
 第一圈:
      h = 31 * h + val[i];->31*0+97 = 97
 第二圈:
     h = 31 * h + val[i]-> 31*97+98 = 3105
 第三圈:
     h = 31 * h + val[i]-> 31*3105+99 = 96354

问题:

为什么要用31去乘?

因为31是一个质数,用31,会降低哈希冲突的概率

6.HashSet的存储去重复的过程

 1.先计算元素的哈希值,然后比较哈希值
 2.如果哈希值不一样,直接存储
 3.如果哈希值一样,再比较元素内容
 4.如果哈希值一样,内容不一样,直接存
 5.如果哈希值一样,内容也一样,直接去重复,后面的会把前面的覆盖掉
 HashSet<String> set = newHashSet<>();
         set.add("abc");
         set.add("abc");
         set.add("通话");
         set.add("重地");
         set.add("吕布");
         set.add("貂蝉");
         System.out.println(set);

7.HashSet存储自定义类型如何去重复

 set集合存储自定义对象,想要去重复,应该重写hashCode和equals方法,去比较属性的哈希值和内容
 public class Person {
     private String name;
     private int age;
 ​
     public Person() {
     }
 ​
     public Person(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 String toString() {
         return "Person{" +
                 "name='" + name + ''' +
                 ", 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);
     }
 ​
     /**
      * 重写之后,比较的是对象中属性的哈希值 
      * @return
      */
     @Override
     public int hashCode() {
         return Objects.hash(name, age);
     }
 }
 ​
 public class Test02 {
     public static void main(String[] args) {
         HashSet<Person> set = new HashSet<>();
         set.add(new Person("柳岩",36));
         set.add(new Person("柳岩",36));
         set.add(new Person("涛哥",16));
         System.out.println(set);
     }
 }
 ​

第十五章.Map集合

image-20220308092638240

1.Map的介绍

 1.概述:Map接口,是双列集合的顶级接口
 2.特点:
   a.无序(除了LinkedHashMap)
   b.无索引
   c.元素都是键值对形式:  key(键) = value(值)
   d.key唯一,value可以重复(如果key重复了,后面的会把前面的覆盖掉)

2.HashMap的介绍以及使用

 1.概述:HashMap 实现 Map接口
 2.特点:
   a.无序
   b.元素都是key value形式
   c.key唯一,value可重复
   d.无索引
 3.数据结构:
   哈希表
 4.常用方法:
   V put(K key, V value)  -> 存储元素
   V remove(Object key)  ->根据key删除对应的键值对
   V get(Object key)  -> 根据key获取对应的value
   boolean containsKey(Object key) ->判断Map中是否包含指定的key
   Collection<V> values()  -> 将Map中所有的value存储到Collection集合中
   
   Set<K> keySet() -> 将Map中所有的key获取出来存到Set集合中 
   Set<Map.Entry<K,V>> entrySet() -> 获取Map中所有的键值对对象,放到set集合中
       
 5.注意:
   如果key重复了,后面的会把前面的覆盖掉,去重复过程和set一毛一样
 public class Test01_HashMap {
     public static void main(String[] args) {
         HashMap<String, String> hashMap = new HashMap<>();
         //V put(K key, V value)  -> 存储元素
         hashMap.put("涛哥","翠儿");
         hashMap.put("黄晓明","杨颖");
         hashMap.put("文章","马伊琍");
         hashMap.put("陈羽凡","白百何");
         hashMap.put("王宝强","马蓉");
         hashMap.put("涛哥","涛嫂");
         hashMap.put(null,null);//HashMap可以存储null键  null值
 ​
         //V remove(Object key)  ->根据key删除对应的键值对,返回的是被删除的value
         String value1 = hashMap.remove("涛哥");
         System.out.println(value1);
 ​
         // V get(Object key)  -> 根据key获取对应的value
         String value2 = hashMap.get("文章");
         System.out.println(value2);
 ​
         // boolean containsKey(Object key) ->判断Map中是否包含指定的key
         boolean result01 = hashMap.containsKey("王宝强");
         System.out.println(result01);
 ​
         //Collection<V> values()  -> 将Map中所有的value存储到Collection集合中
         Collection<String> collection = hashMap.values();
         System.out.println(collection);
 ​
         System.out.println(hashMap);
 ​
     }
 }

3.HashMap的两种遍历方式

3.1 方式1:获取key,然后根据key获取value

  Set<K> keySet() -> 将Map中所有的key获取出来存到Set集合中
 public class Test02_HashMap {
     public static void main(String[] args) {
         HashMap<String, String> hashMap = new HashMap<>();
         hashMap.put("黄晓明","杨颖");
         hashMap.put("贾乃亮","李小璐");
         hashMap.put("李睿","罗玉凤");
         hashMap.put("征牛","乔碧萝");
 ​
         Set<String> set = hashMap.keySet();
         //遍历set集合将key遍历出来
         for (String key : set) {
             //根据key获取value
             String value = hashMap.get(key);
             System.out.println(key+"..."+value);
         }
     }
 }

3.2 方式2:同时获取key和value

image-20220308102829319

 Set<Map.Entry<K,V>> entrySet() -> 获取Map中所有的键值对对象,放到set集合中
 public class Test03_HashMap {
     public static void main(String[] args) {
         HashMap<String, String> hashMap = new HashMap<>();
         hashMap.put("黄晓明","杨颖");
         hashMap.put("贾乃亮","李小璐");
         hashMap.put("李睿","罗玉凤");
         hashMap.put("征牛","乔碧萝");
 ​
         //先获取记录这key和value的结婚证-> Map.Entry->将Map.Entry对象放到Set集合中
         Set<Map.Entry<String, String>> set = hashMap.entrySet();
         //遍历set集合,将Map.Entry获取出来
         for (Map.Entry<String, String> entry : set) {
             //利用Map.Entry中的getKey方法获取key
             String key = entry.getKey();
             //利用Map.Entry中的getValue方法获取value
             String value = entry.getValue();
 ​
             System.out.println(key+"..."+value);
         }
     }
 }
 ​

4.HashMap存储自定义对象

 1.key存储自定义对象, value类型随意
 2.要想让自定义对象作为key保持唯一,自定义对象需要重写hashCode和equals方法,比较的是属性值
 public class Person {
     private String name;
     private int age;
 ​
     public Person() {
     }
 ​
     public Person(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 String toString() {
         return "Person{" +
                 "name='" + name + ''' +
                 ", 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);
     }
 }
 ​
 public class Test04_HashMap {
     public static void main(String[] args) {
         HashMap<Person, String> map = new HashMap<>();
         map.put(new Person("涛哥",14),"廊坊");
         map.put(new Person("涛哥",14),"霸州");
         map.put(new Person("翠儿",45),"北京");
         map.put(new Person("柳岩",36),"湖南");
 ​
         Set<Person> set = map.keySet();
         for (Person person : set) {
             System.out.println(person.getName()+"..."+person.getAge());
         }
         System.out.println("============================");
         //遍历获取value
         Set<Map.Entry<Person, String>> set1 = map.entrySet();
         for (Map.Entry<Person, String> entry : set1) {
             Person person = entry.getKey();
             String value = entry.getValue();
             System.out.println(person.getName()+"..."+person.getAge()+"..."+value);
         }
 ​
     }
 }
 ​

5.Map的练习

 需求:利用HashMap集合统计字符串中字符出现的次数
 实现步骤:
   1.使用Scanner键盘录入一个字符串
   2.创建一个Map集合 key保存字符  value保存字符个数
   3.遍历字符串,将每一个字符遍历出来
   4.判断,map中是否包含遍历出来的字符
   5.如果不包含,直接将字符 和 1存进去
   6.如果包含,根据字符将value获取出来,进行加1
   7.再将此字符,和变化之后的value重新存进去

image-20220308111329612

 public class Test05_HashMap {
     public static void main(String[] args) {
         //1.使用Scanner键盘录入一个字符串
         Scanner sc = new Scanner(System.in);
         System.out.println("请你输入一个字符串:");
         String data = sc.next();
         //2.创建一个Map集合 key保存字符  value保存字符个数
         HashMap<String, Integer> map = new HashMap<>();
         //3.遍历字符串,将每一个字符遍历出来
         char[] chars = data.toCharArray();
         for (char aChar : chars) {
             String key = aChar+"";
         //4.判断,map中是否包含遍历出来的字符
             if (!map.containsKey(key)){
         //5.如果不包含,直接将字符 和 1存进去
                map.put(key,1);
             }else{
         //6.如果包含,根据字符将value获取出来,进行加1
                 Integer value = map.get(key);
                 value++;
         //7.再将此字符,和变化之后的value重新存进去
                 map.put(key,value);
             }
 ​
         }
 ​
         System.out.println(map);
     }
 }
 ​

6.LinkedHashMap

 1.概述:LinkedHashMap extends HashMap
 2.特点:
   a.有序
   b.key唯一
   c.无索引
   d.元素为key value形式
 3.数据结构:
   哈希表+双链表
 4.使用,和LHashMap一样
 public class Test06_LinkedHashMap {
     public static void main(String[] args) {
         LinkedHashMap<String, String> map = new LinkedHashMap<>();
         map.put("黄晓明","杨颖");
         map.put("贾乃亮","李小璐");
         map.put("李睿","罗玉凤");
         map.put("征牛","乔碧萝");
         System.out.println(map);
 ​
         Set<String> set = map.keySet();
         for (String key : set) {
             String value = map.get(key);
             System.out.println(key+"="+value);
         }
         System.out.println("===================");
         Set<Map.Entry<String, String>> set1 = map.entrySet();
         for (Map.Entry<String, String> entry : set1) {
             System.out.println(entry.getKey()+"..."+entry.getValue());
         }
     }
 }
 ​

7.斗地主_Map版本

image-20220308113422480

 public class Test07_Poker {
     public static void main(String[] args) {
         //1.创建HashMap集合
         HashMap<Integer, String> poker = new HashMap<>();
         //2.准备花色和牌号
         String[] pokerNumber = "2-3-4-5-6-7-8-9-10-J-Q-K-A".split("-");
         String[] pokerColor = "♠-♥-♣-♦".split("-");
 ​
         //3.创建一个专门存储key的ArrayList集合
         ArrayList<Integer> list = new ArrayList<>();
 ​
         int index = 2;
         for (String number : pokerNumber) {
             for (String color : pokerColor) {
                 String element = color+number;
                 poker.put(index,element);
                 list.add(index);
                 index++;
             }
         }
 ​
         //4.专门存大小王
         poker.put(0,"大💀");
         poker.put(1,"小💀");
         list.add(0);
         list.add(1);
 ​
         //5.洗牌
         Collections.shuffle(list);
         //6.发牌
         ArrayList<Integer> player1 = new ArrayList<>();
         ArrayList<Integer> player2 = new ArrayList<>();
         ArrayList<Integer> player3 = new ArrayList<>();
         ArrayList<Integer> dipai = new ArrayList<>();
 ​
         for (int i = 0; i < list.size(); i++) {
             Integer key = list.get(i);
             if (i>=51){
                 dipai.add(key);
             }else{
                if (i%3==0){
                    player1.add(key);
                }else if(i%3==1){
                    player2.add(key);
                }else{
                    player3.add(key);
                }
             }
         }
 ​
         //7.排序
         Collections.sort(player1);
         Collections.sort(player2);
         Collections.sort(player3);
         Collections.sort(dipai);
 ​
         look("涛哥",player1,poker);
         look("翠儿",player2,poker);
         look("静静",player3,poker);
         look("底牌",dipai,poker);
     }
 ​
     public static void look(String name,ArrayList<Integer> list,HashMap<Integer, String> map){
         System.out.print(name+":");
         for (Integer key : list) {
             String poker = map.get(key);
             System.out.print(poker+"\t");
         }
         System.out.println();
     }
 }
 ​

第十六章.TreeSet

 1.概述:TreeSetSet接口的实现类
 2.特点:
   a.可以对元素进行排序
   b.元素唯一
   c.无索引
 3.数据结构:
   红黑树
 ​
 构造:
  TreeSet() -> 对元素进行自然排序
  TreeSet(Comparator<? super E> comparator) -> 对元素按照指定的规则进行排序
 public class Test01_TreeSet {
     public static void main(String[] args) {
         //TreeSet() -> 对元素进行自然排序
         TreeSet<String> treeSet = new TreeSet<>();
         treeSet.add("d");
         treeSet.add("c");
         treeSet.add("a");
         treeSet.add("b");
         System.out.println(treeSet);
     }
 }
 public class Person {
     private String name;
     private int age;
 ​
     public Person() {
     }
 ​
     public Person(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 String toString() {
         return "Person{" +
                 "name='" + name + ''' +
                 ", 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);
     }
 }
 ​
 public class Test02_TreeSet {
     public static void main(String[] args) {
         // TreeSet(Comparator<? super E> comparator) -> 对元素按照指定的规则进行排序
         TreeSet<Person> treeSet = new TreeSet<>(new Comparator<Person>() {
             @Override
             public int compare(Person o1, Person o2) {
                 return o1.getAge()-o2.getAge();
             }
         });
         treeSet.add(new Person("柳岩",36));
         treeSet.add(new Person("涛哥",18));
         treeSet.add(new Person("翠儿",16));
         System.out.println(treeSet);
     }
 }
 ​

第十七章.TreeMap

 1.概述:TreeMap 是 Map的实现类
 2.特点:
   a.可以对key进行排序
   b.元素都是key value形式
   c.无索引
   d.key唯一
 3.底层数据结构:
   红黑树
 TreeMap() -> 可以对key进行自然排序
 TreeMap(Comparator<? super K> comparator) -> 对key进行指定规则的排序
 public class Test03_TreeMap {
     public static void main(String[] args) {
         TreeMap<String, String> treeMap = new TreeMap<>();
         treeMap.put("d","低头思故乡");
         treeMap.put("b","疑是地上霜");
         treeMap.put("a","床前明月光");
         treeMap.put("c","举头望明月");
 ​
         System.out.println(treeMap);
     }
 }
 public class Person {
     private String name;
     private int age;
 ​
     public Person() {
     }
 ​
     public Person(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 String toString() {
         return "Person{" +
                 "name='" + name + ''' +
                 ", 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);
     }
 }
 ​
 public class Test04_TreeMap {
     public static void main(String[] args) {
         TreeMap<Person, String> treeMap = new TreeMap<>(new Comparator<Person>() {
             @Override
             public int compare(Person o1, Person o2) {
                 return o1.getAge()-o2.getAge();
             }
         });
         treeMap.put(new Person("柳岩",36),"湖南");
         treeMap.put(new Person("涛哥",18),"河北");
         treeMap.put(new Person("翠儿",45),"北京");
         System.out.println(treeMap);
     }
 }
 ​

第十八章.HashTable和Vector集合(了解)

1.HashTable集合

 1.概述:开始于JDK1.0 ,从Java 2 平台 v1.2起,此类就被改进以实现 Map 接口
 2.特点:
   a.key唯一
   b.无索引
   c.无序
   d.线程安全,效率低
 3.数据结构:
   哈希表
 4.使用:
   和HashMap一毛一样
 public class Test01_HashTable {
     public static void main(String[] args) {
         Hashtable<String, String> hashtable = new Hashtable<>();
         hashtable.put("张三","李四");
         hashtable.put("王五","赵六");
         hashtable.put("田七","猪八");
         hashtable.put("涛哥","柳岩");
         hashtable.put("涛哥","杨幂");
         System.out.println(hashtable);
 ​
         Set<String> set = hashtable.keySet();
         for (String key : set) {
             String value = hashtable.get(key);
             System.out.println(key+"="+value);
         }
 ​
         System.out.println("=======================");
 ​
         Set<Map.Entry<String, String>> set1 = hashtable.entrySet();
         for (Map.Entry<String, String> entry : set1) {
             System.out.println(entry.getKey());
             System.out.println(entry.getValue());
         }
     }
 }
 ​

2.Vector集合

 1.概述:出现在jdk1.0版本,从 Java 2 平台 v1.2 开始,此类改进为可以实现 List 接口
 2.特点:
   a.有序
   b.有索引
   c.元素可重复
   d.线程安全,效率低
 3.数据结构:
   数组
 4.使用:和ArrayList一样
 5.底层分析:
   a.Vectornew底层就会直接产生一个长度为10的空数组
   b.数组扩容:Arrays.copyOf
     扩容2
 public class Test02_Vector {
     public static void main(String[] args) {
         Vector<Integer> vector = new Vector<>();
         vector.add(1);
         vector.add(2);
         System.out.println(vector);
     }
 }
 ​

笔试题:Hashtable和HashMap区别

 1.相同点:
 都是哈希表结构,都是key唯一,无索引,无序
 2.不同点:
 HashMap:线程不安全,效率高,能存储null键,null值
 Hashtable:线程安全,效率低,不能存储null键,null

第十九章.Properties集合(属性集)

 1.概述:Properties extends Hashtable
 2.特点:
   a.无序
   b.无索引
   c.key唯一
   d.key value 固定都是String
   e.不能存储null键 null值
   f.线程安全,效率低
 3.数据结构:
   哈希表
 4.使用:和HashMap一样,HashMap中的方法Properties集合都能使用
 5.这里我不学HashMap的方法,我们要学Properties的特有方法
   Object setProperty(String key, String value)  -> 存储键值对
   String getProperty(String key)  -> 根据key获取value
   Set<String> stringPropertyNames()  -> 获取所有的key,存放到Set集合中
       
   void load(InputStream inStream)  ->  将流中的数据信息加载到Properties集合中 (IO流部分讲)
 public class Test01 {
     public static void main(String[] args) {
         Properties properties = new Properties();
         //Object setProperty(String key, String value)  -> 存储键值对
         properties.setProperty("username","root");
         properties.setProperty("password","1234");
         System.out.println(properties);
         //String getProperty(String key)  -> 根据key获取value
         System.out.println(properties.getProperty("username"));
         //Set<String> stringPropertyNames()  -> 获取所有的key,存放到Set集合中,类似于keySet方法
         Set<String> set = properties.stringPropertyNames();
         for (String key : set) {
             System.out.println(properties.getProperty(key));
         }
 ​
     }
 }

Properties的使用场景:配合IO流解析配置文件中的数据

 我们可以将一些硬数据,放到配置文件中,然后动态解析配置文件,读取配置文件中的数据,也可以更好的降低耦合度
 1.创建一个后缀名为.properties的文件->properties文件
 2.在配置文件中写key=value
 username=root
 password=1234
 public class Test02 {
 public static void main(String[] args) throws Exception {
   //创建字节输入流,读取配置文件
   FileInputStream fis = new FileInputStream("day18\pro.properties");
   //创建properties集合
   Properties properties = new Properties();
   // void load(InputStream inStream)  ->  将流中的数据信息加载到Properties集合中 (IO流部分讲)
   properties.load(fis);
 ​
   System.out.println(properties);
 }
 }

第二十章.集合嵌套

1.List嵌套List

 需求:创建2个List集合,每个集合中分别存储一些字符串,将2个集合存储到第3个List集合中
 public class Test01_List_in_List {
     public static void main(String[] args) {
         ArrayList<String> list1 = new ArrayList<>();
         list1.add("杨过");
         list1.add("尹志平");
         list1.add("小龙女");
         ArrayList<String> list2 = new ArrayList<>();
         list2.add("周芷若");
         list2.add("张无忌");
         list2.add("赵敏");
 ​
         //创建第三个集合
         ArrayList<ArrayList<String>> list = new ArrayList<>();
         list.add(list1);
         list.add(list2);
 ​
         //遍历,先遍历大list,将list1和list2遍历出来
         for (ArrayList<String> arrayList : list) {
            //遍历list1和list2
             for (String s : arrayList) {
                 System.out.println(s);
             }
         }
 ​
     }
 }

2.List嵌套Map

 1班级有第三名同学,学号和姓名分别为:1=张三,2=李四,3=王五,2班有三名同学,学号和姓名分别为:1=黄晓明,2=杨颖,3=刘德华,请将同学的信息以键值对的形式存储到2个Map集合中,在将2个Map集合存储到List集合中。
 public class Test02_List_in_Map {
     public static void main(String[] args) {
         //创建两个map集合
         HashMap<Integer, String> map1 = new HashMap<>();
         map1.put(1,"张三");
         map1.put(2,"李四");
         HashMap<Integer, String> map2 = new HashMap<>();
         map2.put(1,"黄晓明");
         map2.put(2,"刘德华");
 ​
         //创建List集合,存储两个map
         ArrayList<HashMap<Integer, String>> list = new ArrayList<>();
         list.add(map1);
         list.add(map2);
 ​
 ​
         //遍历List集合,将小Map获取出来
         for (HashMap<Integer, String> map : list) {
             //遍历小map,将key value获取出来
             Set<Map.Entry<Integer, String>> set = map.entrySet();
             for (Map.Entry<Integer, String> entry : set) {
                 System.out.println(entry.getKey()+"="+entry.getValue());
             }
         }
         
     }
 }

3.Map嵌套Map

 - JavaSE  集合 存储的是 学号 键,值学生姓名
   - 1  张三
   - 2  李四
 - JavaEE 集合 存储的是 学号 键,值学生姓名
   - 1  王五
   - 2  赵六
 public class Test03_Map_in_Map {
     public static void main(String[] args) {
         //创建小map
         HashMap<Integer, String> map1 = new HashMap<>();
         map1.put(1,"张三");
         map1.put(2,"李四");
         HashMap<Integer, String> map2 = new HashMap<>();
         map2.put(1,"王五");
         map2.put(2,"赵六");
 ​
         HashMap<String, HashMap<Integer, String>> map = new HashMap<>();
         map.put("javase",map1);
         map.put("javaee",map2);
 ​
         //遍历大map
         Set<String> set = map.keySet();
         for (String key : set) {
             HashMap<Integer, String> hashMap = map.get(key);
             //遍历小map
             Set<Map.Entry<Integer, String>> entries = hashMap.entrySet();
             for (Map.Entry<Integer, String> entry : entries) {
                 System.out.println(entry.getKey()+"="+entry.getValue());
             }
         }
     }
 }

第二十一章.正则表达式

1.正则表达式的概念及演示

 1.概述:是字符串表示的一个规则
 2.作用:用于校验
 3.需求:QQ号
   a.开头不能是0
   b.必须都是数字
   c.QQ号必须是5-15位
     
   正则表达式:[1-9][0-9]{4,14}
 4.String中有一个方法:
   boolean matches(String regex)->判断某个字符串是否符合regex正则表达式规则
 public class Demo01_Regex {
     public static void main(String[] args) {
         Scanner sc = new Scanner(System.in);
         System.out.println("请你输入一个QQ号:");
         String QQ = sc.next();
         //boolean result = method(QQ);
         //System.out.println("result = " + result);
 ​
         boolean result01 = method01(QQ);
         System.out.println("result01 = " + result01);
     }
 ​
     private static boolean method01(String qq) {
         boolean result = qq.matches("[1-9][0-9]{4,14}");
         return result;
     }
 ​
     /*
         a.开头不能是0
         b.必须都是数字
         c.QQ号必须是5-15位
      */
     private static boolean method(String qq) {
         //a.开头不能是0
         if (qq.startsWith("0")){
             return false;
         }
 ​
         // b.必须都是数字
         char[] chars = qq.toCharArray();
         for (char aChar : chars) {
             if (aChar<'0' || aChar>'9'){
                 return false;
             }
         }
 ​
 ​
         //QQ号必须是5-15位
         if (qq.length()<5 || qq.length()>15){
             return false;
         }
 ​
         return true;
     }
 }

2.正则表达式-字符类

 java.util.regex.Pattern:正则表达式的编译表示形式。
     正则表达式-字符类:[]表示一个区间,范围可以自己定义
         语法示例:
         1. [abc]:代表a或者b,或者c字符中的一个。
         2. [^abc]:代表除a,b,c以外的任何字符。
         3. [a-z]:代表a-z的所有小写字符中的一个。
         4. [A-Z]:代表A-Z的所有大写字符中的一个。
         5. [0-9]:代表0-9之间的某一个数字字符。
         6. [a-zA-Z0-9]:代表a-z或者A-Z或者0-9之间的任意一个字符。
         7. [a-dm-p]admp之间的任意一个字符      
 public class Demo02_Regex {
     public static void main(String[] args) {
         //1.验证字符串是否以h开头,d结尾,中间是aeiou的某一个字符
         boolean result01 = "hyd".matches("[h][aeiou][d]");
         System.out.println(result01);
 ​
         //2.验证字符串是否以h开头,d结尾,中间不是aeiou的某一个字符
         boolean result02 = "hyd".matches("[h][^aeiou][d]");
         System.out.println(result02);
 ​
         //3.验证字符串是否是a-z的任意一个小写字母开头,后面是ad
         boolean result03 = "aad".matches("[a-z][a][d]");
         System.out.println("result03 = " + result03);
     }
 }
 ​

3.正则表达式-逻辑运算符

  正则表达式-逻辑运算符
         语法示例:
         1. &&:并且
         2. | :或者 
 public class Demo03_Regex {
     public static void main(String[] args) {
         //1.要求字符串是小写[a-z],并且字符[^aeiou]开头,后面跟ad
         boolean result01 = "aad".matches("[[a-z]&&[^aeiou]][a][d]");
         System.out.println("result01 = " + result01);
 ​
         //2.要求字符串是aeiou中的某一个字母开头,后跟ad
         boolean result02 = "add".matches("[a|e|i|o|u][a][d]");
         System.out.println("result02 = " + result02);
     }
 }
 ​

4.正则表达式-预定义字符

  正则表达式-预定义字符
     语法示例:
     1. "." : 匹配任何字符。(重点)
     2. "\d":任何数字[0-9]的简写;(重点)
     3. "\D":任何非数字[^0-9]的简写;
     4. "\s": 空白字符:[ \t\n\x0B\f\r] 的简写
     5. "\S": 非空白字符:[^\s] 的简写
     6. "\w":单词字符:[a-zA-Z_0-9]的简写(重点)
     7. "\W":非单词字符:[^\w]
 public class Demo04_Regex {
     public static void main(String[] args) {
         //1.验证字符串是否是三位数字
         boolean result01 = "111".matches("\d\d\d");
         System.out.println("result01 = " + result01);
 ​
         //2.验证手机号:1开头  第二位 3  5  8  剩下的9位都是0-9的数字
         boolean result02 = "13838381438".matches("[1][358]\d\d\d\d\d\d\d\d\d");
         System.out.println("result02 = " + result02);
 ​
         //3.验证字符串是否以h开头,d结尾,中间是任意一个字符
         boolean result03 = "had".matches("[h].[d]");
         System.out.println("result03 = " + result03);
     }
 }

5. 正则表达式-数量词

  正则表达式-数量词
         语法示例:x代表字符
         1. X? : x出现的数量为 0次或1次
         2. X* : x出现的数量为 0次到多次 任意次
         3. X+ : x出现的数量为 1次或多次 X>=1次
         4. X{n} : x出现的数量为 恰好n次 X=n次
         5. X{n,} : x出现的数量为 至少n次 X>=n次  x{3,}
         6. X{n,m}: x出现的数量为 n到m次(n和m都是包含的)   n=<X<=m
 public class Demo05_Regex {
     public static void main(String[] args) {
         //1.验证字符串是否是三位数字
         boolean result01 = "1111".matches("\d{3}");
         System.out.println("result01 = " + result01);
 ​
         //2.验证手机号:1开头  第二位 3  5  8  剩下的9位都是0-9的数字
         boolean result02 = "13838381438".matches("[1][358]\d{9}");
         System.out.println("result02 = " + result02);
 ​
         //3.qq号:不能是0开头  都是数字  5-15
         boolean result03 = "11111111".matches("[1-9][0-9]{4,14}");
         System.out.println("result03 = " + result03);
 ​
     }
 }

6.正则表达式-分组括号( )

 正则表达式-分组括号( )
 public class Demo06_Regex {
     public static void main(String[] args) {
         //校验字符串abc可以出现任意次
         boolean result01 = "abcabcabcabc".matches("(abc)*");
         System.out.println("result01 = " + result01);
     }
 }
 ​

7.String类中和正则表达式相关的方法

  String类中和正则表达式相关的方法
         boolean matches(String regex) 判断字符串是否匹配给定的正则表达式。
         String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。
         String replaceAll(String regex, String replacement)把满足正则表达式的字符串,替换为新的字符
 public class Demo07_Regex {
     public static void main(String[] args) {
         //String[] split(String regex) 根据给定正则表达式的匹配拆分此字符串。
         String[] s = "abc haha   呵呵呵".split(" +");
         System.out.println(Arrays.toString(s));
 ​
         //String replaceAll(String regex, String replacement)把满足正则表达式的字符串,替换为新的字符
 ​
         String s1= "abc haha 诶嘿IEhi  哈哈哈哈哈";
         String s2 = s1.replaceAll(" +", "z");
         System.out.println(s2);
 ​
     }
 }

8.正则表达式生成网址:

 https://www.sojson.com/regex/generate