java从零开始系统性学习完整超全资源+笔记(下)

java从零开始系统性学习完整超全资源+笔记(下)

java从零开始系统性学习完整超全资源+笔记(上)

文章目录

  • java从零开始系统性学习完整超全资源+笔记(下)
    • 第十七章 泛型与常见数据结构
      • ArrayList
      • Collection接口的实现
      • 泛型 generics
      • 迭代器Iterator
      • foreach
      • 常见的数据结构
        • 数组
        • 链表
      • 栈和队列
      • List
      • LinkedList
      • 案例 查找元素索引及判断元素是否存在案例
      • 练习
    • 第十八章 Set与Map集合
      • Set
      • 增强for循环
      • hashSet
      • 方法重载与重写
      • hashCode方法和equals方法的优化
      • Collection
        • 定义
        • Collection和Collections有什么区别?
        • collection方法
      • Collection练习 模拟斗地主
      • Map
        • Map和Collection有什么区别?
        • map常用功能
        • map的两种遍历方式
        • Map的第二种遍历方式
        • 使用HashMap存储数据并遍历(字符串作为key)
        • 使用HashMap存储数据并遍历(自定义对象作为key)
    • 第十九章 异常的处理
      • 异常的概述和体系结构.
      • JVM处理异常的方式
      • 如何处理多个异常
      • Throwable的常用方法
      • finally概述和应用场景
      • 异常的分类
      • 自定义异常
      • 递归概述和例题
    • 第二十章 多线程
      • 线程概述
        • 进程
        • 线程
      • 多线程的实现
      • 线程相关方法
      • 线程安全

第十七章 泛型与常见数据结构

ArrayList
集合的体系结构:
由于不同的数据结构(数据的组织,存储方式),所以Java为我们提供了不同的集合,
但是不同的集合他们的功能都是相似,不断的向上提取,将共性抽取出来,这就是集合体系结构形成的原因
体系结构:
怎么学习?最顶层开始学习,因为最顶层包含了所有的共性
怎么使用?使用最底层,因为最底层就是具体的实现
Collection
List

ArrayList

package com.demo01;

import java.util.ArrayList;

/*
 *  ArrayList
 *  集合的体系结构:
 *  	由于不同的数据结构(数据的组织,存储方式),所以Java为我们提供了不同的集合,
 *  	但是不同的集合他们的功能都是相似,不断的向上提取,将共性抽取出来,这就是集合体系结构形成的原因
 *  
 *  体系结构:
 *  		怎么学习?最顶层开始学习,因为最顶层包含了所有的共性
 *  		怎么使用?使用最底层,因为最底层就是具体的实现
 *  
 *  Collection
 *  List
 *  ArrayList
 */
public class CollectionDemo {
	public static void main(String[] args) {		
		//创建集合对象
		ArrayList al = new ArrayList();
		//添加元素
		al.add("hello");
		al.add("world");
		al.add("java");
		//遍历集合
		for(int x = 0;x < al.size();x++) {
			System.out.println(al.get(x));
		}
		
	}
}

Collection接口的实现

Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:**它提供更具体的子接口(如 Set 和 List)**实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。

/*
 * 	Collection接口的实现
 * 			boolean add(E e) 确保此 collection 包含指定的元素(可选操作)。
 * 			void clear() 移除此 collection 中的所有元素(可选操作)。
 * 			boolean contains(Object o) 如果此 collection 包含指定的元素,则返回 true。
 * 			boolean isEmpty() 如果此 collection 不包含元素,则返回 true。
 * 			boolean remove(Object o) 从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。
 * 			int size() 返回此 collection 中的元素数。
 * 			Object[] toArray()  返回包含此 collection 中所有元素的数组。
 * 		如果此 collection 包含指定的元素,则返回 true。更确切地讲,当且仅当此 collection 至少包含一个满足 (o==null ? e==null : o.equals(e)) 的元素 e 时,返回 true。
 */
package CollectionDemo;

import java.util.ArrayList;
import java.util.Objects;


public class ArrayListDemo2 {
    public static void main(String[] args) {
        ArrayList a = new ArrayList();
//        1.boolean add(E e)
        a.add("hello1");    //add的时候运行没有东西,必须打印出来才有
        a.add("hello2");
//        2.void clear()
//        a.clear();
        for(int i = 0;i<a.size();i++){
            System.out.println(a.get(i));
        }
//      3.boolean contains(Object o)
        boolean flag = a.contains("hello1");    //包含就返回true
        System.out.println(flag);
        System.out.println(a);
//        boolean isEmpty()
        boolean flag1 = false;
        if(a!=null&&a.isEmpty()){
            flag1 = true;
            System.out.println(flag);
        }
//        boolean remove(Object o)
        boolean f = a.remove("hello1");
        System.out.println(f);
        System.out.println(a);
        int size = a.size();
        System.out.println(size);
//        Object[] toArray()
        Object[] objects = a.toArray();
        for(int i = 0;i< objects.length;i++){
            System.out.println(objects[i]);
        }
    }
}

泛型 generics

使用集合存储自定义对象并遍历
 * 由于集合可以存储任意类型的对象,当我们存储了不同类型的对象,就有可能在转换的时候出现类型转换异常,
 * 所以java为了解决这个问题,给我们提供了一种机制,叫做泛型
 * 
 * 泛型:是一种广泛的类型,把明确数据类型的工作提前到了编译时期,借鉴了数组的特点
 * 泛型好处:
 * 			避免了类型转换的问题
 * 			可以减少黄色警告线
 * 			可以简化我们代码的书写 不用强制类型转换
 * 
 * 什么时候可以使用泛型?
 * 		问API,当我们看到<E>,就可以使用泛型了
 List ArrayList Collection 等都可以用泛型

使用泛型的缺点
虽然泛型在很多情况下能够提供强类型检查和代码重用的好处,但它们也有一些缺点,包括以下几点:

**增加代码复杂性**:泛型代码通常比非泛型代码更复杂,因为它需要在类型安全的同时支持多种数据类型。这可能导致代码更难理解和维护。

**增加编译时间**:泛型代码通常需要更多的编译时间,因为编译器必须在编译时生成并检查泛型类型的代码。这可能会导致较长的编译时间,特别是在使用大量泛型的大型项目中。

受限于类型擦除:在 Java 中,泛型类型信息在编译时被擦除,这意味着在运行时无法访问泛型类型的信息。这可以导致一些类型转换和类型安全问题,尤其是在处理复杂的泛型类型时。

需要额外的学习和使用成本:泛型是一种相对较新的编程技术,因此需要额外的学习成本。此外,对于一些简单的应用程序,使用泛型可能是过度设计,这可能会增加使用成本和复杂性。

综上所述,泛型的使用虽然有很多好处,但也需要仔细考虑其使用场景和实际需求,以平衡其优点和缺点。

例如
java从零开始系统性学习完整超全资源+笔记(下)_第1张图片

package CollectionDemo;

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

/*泛型概述
使用集合可以存储任意类型的对象,由于存储了不同类型的对象,有可能在转换的时候
出现类型转换异常。所以java为了解决这个问题,提供了一种机制generic泛型
泛型:是一种广泛的类型,把明确数据类型的工作提前到了编译时期,借鉴了数组的特点
泛型的好处:
    避免类型转换的问题
    可以减少黄色警告线
    简化代码书写 不用强制类型转换
什么时候用泛型?
    问API,当我们看到就可以使用泛型
    List ArrayList Collection等都可以用泛型
 */
public class GenericDemo {
    public static void main(String[] args) {
/*
//        不知道集合里面的类型是什么,所以用泛型解决这个问题
//        Iterator 是一个接口,用于遍历集合(如 List、Set、Map 等)中的元素
        Collection c = new ArrayList();
        c.add("hello");
        Iterator iterator = c.iterator();
        int i = (int) iterator.next();
        System.out.println(i);
//出现异常 java.lang.String cannot be cast to java.lang.Integer
*/

//        创建集合对象
        Collection<Student> c = new ArrayList<Student>();
//        创建元素对象
        Student s1 = new Student("zhangsan1",13);
        Student s2 = new Student("zhangsan2",16);
//         添加元素对象
        c.add(s1);
        c.add(s2);
//        遍历元素对象
        Iterator<Student> it = c.iterator();
        while (it.hasNext()){
            Student stu = it.next();
            System.out.println(stu.name);
        }
    }
    static class Student{
        String name;
        int age;
        public Student(String name,int age){
            this.name = name;
            this.age = age;
        }
    }
}

package com.demo03;

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

/*
 * 使用集合存储自定义对象并遍历
 * 由于集合可以存储任意类型的对象,当我们存储了不同类型的对象,就有可能在转换的时候出现类型转换异常,
 * 所以java为了解决这个问题,给我们提供了一种机制,叫做泛型
 * 
 * 泛型:是一种广泛的类型,把明确数据类型的工作提前到了编译时期,借鉴了数组的特点
 * 泛型好处:
 * 			避免了类型转换的问题
 * 			可以减少黄色警告线
 * 			可以简化我们代码的书写 不用强制类型转换
 * 
 * 什么时候可以使用泛型?
 * 		问API,当我们看到,就可以使用泛型了
 List ArrayList都可以用泛型
 * 			
 */
public class GenericDemo {
	public static void main(String[] args) {
		/*	Collection c = new ArrayList();
			c.add("Hello");
			
			Iterator iterator = c.iterator();
			int i = (int) iterator.next();
			
			System.out.println(i);
			
			*/
		
		
		//String[] s =new String[3];
		
		
		//创建集合对象
		Collection<Student> c = new ArrayList<Student>();
		//创建元素对象
		Student s = new Student("zhangsan",18);
		Student s2 = new Student("lisi",19);
		//添加元素对象
		c.add(s);
		c.add(s2);
		//遍历集合对象
		
		Iterator<Student> it = c.iterator();
		while(it.hasNext()) {
			
			Student stu = it.next();
			System.out.println(stu.name);
		}
	}
}

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

迭代器Iterator

chatGPT回答
在 Java 中,Iterator 是一个接口,用于**遍历集合(如 List、Set、Map 等)中的元素**。Iterator 接口定义了访问和移除集合中元素的方法,可以帮助开发者逐个访问集合中的元素,而不需要暴露底层数据结构的实现细节。

Iterator 接口包含以下几个方法:

hasNext():返回集合中是否还有下一个元素。
next():返回下一个元素。
remove():从集合中移除上一次返回的元素(可选操作)。
使用 Iterator 遍历集合的基本流程是:首先通过集合对象的 iterator() 方法获得 Iterator 实例,然后通过调用 hasNext() 和 next() 方法逐个访问集合中的元素,最后使用 remove() 方法删除元素(如果需要)。

Iterator 接口的出现使得遍历集合变得更加方便和灵活,同时也提高了代码的可读性和可维护性。

在使用迭代器进行遍历的时候使用迭代器来进行修改
java从零开始系统性学习完整超全资源+笔记(下)_第2张图片
iterator() 可以返回一个迭代器对象,我们可以通过迭代器对象来迭代集合

  • Iterator:可用于遍历集合
  • E next()返回下一个元素
  • boolean hasNext():判断元素是否可以获取
package CollectionDemo;

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

/*
* 集合的遍历方式
*   1.toArray() 可以将集合转化成数组,然后遍历数组即可
*   2.iterator() 可以返回一个迭代器对象,我们可以通过迭代器对象来迭代集合
* Iterator:可用于遍历集合
* E next()返回下一个元素
* boolean hasNext():判断元素是否可以获取
* 注意:Exception in thread "main" java.util.NoSuchElementException
* 使用next方法获取下一个元素,如果没有元素可以获取,则出现NoSuchElementException
* */
public class IteratorDemo1 {
    public static void main(String[] args) {
//        创建集合对象
        Collection c = new ArrayList();
//        添加元素
        c.add("hello1");
        c.add("hello2");
//        获取数组
        Object[] objs = c.toArray();
//        遍历数组
        for (int i = 0; i < objs.length; i++) {
            System.out.println(objs[i]);
        }
    }
}
/*运行结果
hello1
hello2
*/
package CollectionDemo;

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

public class IteratorDemo2 {
    public static void main(String[] args) {
        //创建集合对象
        Collection c = new ArrayList();
        //添加元素
        c.add("hello1");
        c.add("hello2");
//        获取迭代器对象
        Iterator it = c.iterator();
//        Object next():返回下一个元素
       /* System.out.println(it.next());
        System.out.println(it.next());
//        输出hello1,hello2
        */

//        boolean hasNext():判断是否有元素可以获取
       /* if(it.hasNext()){
            System.out.println(it.next());
        }   //输出hello1*/
        while (it.hasNext()){
            System.out.println(it.next());
        }   //输出 hello1 hello2
    }
}

package CollectionDemo;

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

/*需求:判断集合中是否包含元素java,如果有则添加元素android
Exception in thread "main" java.util.ConcurrentModificationException:并发修改异常
迭代器是依赖集合的,相当于集合的一个副本,当迭代器在操作的时候如果发现和迭代器不一样就抛出异常
解决方案:
    别使用迭代器
    在使用迭代器进行遍历的时候使用迭代器来进行修改
* */
public class IteratorDemo3 {
    public static void main(S,,,,,,,,,,,,,,,tring[] args) {
//        创建集合对象
        List c = new ArrayList();
//        添加元素
        c.add("hello1");
        c.add("hello2");
        c.add("java");
        System.out.println(c);
//        通过遍历集合中的每一个元素来比较判断是否包含java
       /* Iterator it = c.iterator();
        while (it.hasNext()){
            String s = (String) it.next();
            if(s.equals("java")){
                c.add("android");
            }
        }
        System.out.println(c);
        Exception in thread "main" java.util.ConcurrentModificationException:并发修改异常
迭代器是依赖集合的,相当于集合的一个副本,当迭代器在操作的时候如果发现和迭代器不一样就抛出异常
        */
        ListIterator lit = c.listIterator();
        while (lit.hasNext()){
            String s =(String)lit.next();
            if(s.equals("java")){
                lit.add("android"); //  在使用迭代器进行遍历的时候使用迭代器来进行修改
            }
        }
        System.out.println(c);

    }
}

foreach

foreach:增强for循环,一般用于遍历集合或者数组
格式:
for(元素的类型 变量 : 集合或者数组对象) {
可以直接使用变量;
}
注意:在增强for循环中不能修改集合,否则会出现并发修改异常,不能进行增减。

public interface Iterable
实现这个接口允许对象成为 "foreach" 语句的目标。
package com.demo04;

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

/*
 * foreach:增强for循环,一般用于遍历集合或者数组
 * 格式:
 * 		for(元素的类型 变量 : 集合或者数组对象) {
 * 			可以直接使用变量;
 * 		}
	注意:在增强for循环中不能修改集合,否则会出现并发修改异常,不能进行增减。

	public interface Iterable
	实现这个接口允许对象成为 "foreach" 语句的目标。

 */
public class ForEachDemo {
    public static void main(String[] args) {
		/* //创建集合对象
		Collection c = new ArrayList();
		//添加元素
		c.add("hello");
		c.add("world");
		c.add("java");

		//增强for循环遍历集合
		for(Object obj : c) {
			System.out.println(obj);
		}


		for(String s : c) {
			s = s.toUpperCase()+"其他的内容";
			System.out.println(s);
		}

		for(String s : c) {
			System.out.println(s);
		}*/

		/*for (String string : c) {
			c.add("android");
			System.out.println(string);
		}*/

        Collection<Student> c = new ArrayList<Student>();
        c.add(new Student("张三",20));
        c.add(new Student("李四",18));

       

        for(Student student:c) {
            System.out.println("name:"+student.name+"  age:"+student.age);
        }
        /* for(Student student:c) { 用foreach对集合修改就出现异常  ConcurrentModificationException:并发修改异常
            System.out.println("name:"+student.name+"  age:"+student.age);
            student.name = student.name+"xx";
            c.add(new Student("王五",22));
        }*/
    }


}

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

}
结果name:张三  age:20
name:李四  age:18

常见的数据结构

数组

数据结构图
java从零开始系统性学习完整超全资源+笔记(下)_第3张图片

特点:1.长度一旦定义就不能被改变;2.数组中的元素都有整数索引;3.数组只能存储同一数据类型的元素;4.数组既可以存储基本数据类型,也可以存储引用数据类型。
优点:检索快,因为可以通过索引获取数组元素
缺点:增加和删除数据慢,因为需要创建新的数据,效率低。
如何插入新的元素?如[1,2,3,4]3后面插入8。
首先创建一个新的数组,长度是原来的数组长度+1;接着遍历原来的数组并存储到新的数组中,遇到3的时候在它后面添加8,最后将剩下的元素添加到8后面即可。

链表

获取结点:
java从零开始系统性学习完整超全资源+笔记(下)_第4张图片
添加结点:
java从零开始系统性学习完整超全资源+笔记(下)_第5张图片
特点:由链子链接起来的一堆结点,有头结点和尾结点
优点:增加和删除元素快
缺点:查询慢,只能遍历列表一个个看
java从零开始系统性学习完整超全资源+笔记(下)_第6张图片

栈和队列

java从零开始系统性学习完整超全资源+笔记(下)_第7张图片
特点:栈:先进后出(子弹出夹);队列:先进先出。(买火车票进站)
优点:
缺点:

List

定义:List 组件为用户提供了一个可滚动的文本项列表。可设置此 list,使其允许用户进行单项或多项选择。

 * List:
 * 		有序的(存储和读取的顺序是一致的)
 * 		有整数索引
 * 		允许重复的
 *
 * List的特有功能:
 * 			void add(int index, E element) 在列表的指定位置插入指定元素
 * 			E get(int index) 根据索引返回元素
 * 			E remove(int index) 删除指定元素并返回
 *  		E set(int index, E element) 将指定索引位置的元素替换为指定元素,并将原先的元素返回
package CollectionDemo;

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

/*
 * List:
 * 		有序的(存储和读取的顺序是一致的)
 * 		有整数索引
 * 		允许重复的
 *
 * List的特有功能:
 * 			void add(int index, E element)
 * 			E get(int index)
 * 			E remove(int index) 删除指定元素并返回
 *  		E set(int index, E element)
 *
 *   增删改查
 */
public class ListDemo {
    public static void main(String[] args) {
        List list =new ArrayList();
//        //void add(int index, E element)  : 在列表的指定位置插入指定元素
        list.add(0,"hello");
        list.add(0,"c++");
        list.add(1,"java");
        System.out.println(list);
//       E get(int index)  :根据索引返回元素
        /*System.out.println(list.get(0));
        System.out.println(list.get(1));
        System.out.println(list.get(2));
        */
        for (int i= 0;i<list.size();i++){
            System.out.println(list.get(i));
        }
//       E remove(int index)  : 删除指定元素并返回
        System.out.println(list.remove(1));
        System.out.println(list);
//    输出    [c++, hello]
//    E set(int index, E element) : 将指定索引位置的元素替换为指定元素,并将原先的元素返回
        System.out.println(list.set(0,"and"));
        System.out.println(list);
//     输出   [and, hello]
    }
}

LinkedList

java从零开始系统性学习完整超全资源+笔记(下)_第8张图片
List的常用子类
ArrayList 底层是数组 增删慢,查询快
LinkedList 底层是链表 增删快,查询慢

如何选择使用不同的集合?
如果查询多,增删少,则使用ArrayList
如果查询少,增删多,则使用LinkedList
如果你不知道使用什么,则使用ArrayList
LinkedList的特有功能:
void addFirst(E e)
void addLast(E e)
E getFirst()
E getLast()
E removeFirst()
E removeLast()

package com.demo06;

import java.util.LinkedList;


 */
public class LinkedListDemo {
	public static void main(String[] args) {
			LinkedList<String> list = new LinkedList<String>();
			list.add("hello");
			list.add("world");
		
			//void addFirst(E e)  :将元素添加到索引为0的位置
 			//void addLast(E e) :将元素添加到索引为size()-1的位置
			//list.addFirst("java");
			
			//list.addLast("android");
			
 			//E getFirst()  :获取索引为0的元素
 			//E getLast()  :获取索引为size()-1的元素
			//System.out.println(list.getFirst());
			//System.out.println(list.getLast());
			System.out.println(list);
 			//E removeFirst() :删除索引为0的元素并返回
 			//E removeLast() :删除索引为size()-1的元素并返回
			//System.out.println(list.removeFirst());
			System.out.println(list.removeLast());
			
			
			System.out.println(list);
	}
}

package CollectionDemo;

import java.util.LinkedList;

/*
List的常用子类
ArrayList 底层是数组 增删慢,查询快
LinkedList 底层是链表 增删快,查询慢
如何选择使用不同的集合?
	如果查询多,增删少,则使用ArrayList
 	如果查询少,增删多,则使用LinkedList
    如果你不知道使用什么,则使用ArrayList
    LinkedList的特有功能:
		void addFirst(E e)
		void addLast(E e)
 			E getFirst()
 			E getLast()
 			E removeFirst()
 			E removeLast()
*/
public class ListedListDemo {
    public static void main(String[] args) {
        LinkedList<String> list = new LinkedList<String>();
        list.add("hello");
        list.add("ho");
        list.addFirst("h");
        list.addLast("yy");
        System.out.println(list);
//      运行结果  [h, hello, ho, yy]
        System.out.println(list.getFirst());    //h
        System.out.println(list.getLast());     //yy
        System.out.println(list.removeFirst()); // h删除索引为0的元素并返回
        System.out.println(list.removeLast());  //yy
        System.out.println(list);   //输出[hello, ho]
    }
}

案例 查找元素索引及判断元素是否存在案例

package com.demo07;

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

/*
 * 需求:定义一个方法,返回指定列表中指定元素的索引位置
 * 
 * 判断元素是否存在
 * 
 */
public class ListTest {
	public static void main(String[] args) {
		List list = new ArrayList();
		list.add("hello");
		list.add("world");
		list.add("java");
		
		int index = index(list,"python");
		System.out.println(index);
		
		boolean flag = contains(list, "world");
		System.out.println(flag);	//输出 1
		
		boolean flag1 = list.contains("java");
		System.out.println(flag1);	// 输出true
	}
	
	public static int index(List list,Object other) {
		for(int x = 0;x < list.size();x++) {
			//获取列表中的元素
			Object obj = list.get(x);
			//使用列表中的元素和指定的元素进行比较
			if(obj.equals(other)) {
				return x;
			}
		}
		//查找不到指定的元素
		return -1;
	}
	
	public static boolean contains(List list,Object other) {
		//获取指定元素在指定列表中的索引位置
		int index = index(list,other);
		//如果索引位置大于等于0,则认为元素存在,否则不存在
		if(index >= 0) {
			return true;
		} else {
			return false;
		}
	}
	
	
	
}

练习

1、
分析以下需求,并用代码实现
(1)生成10个1至100之间的随机整数(不能重复),存入一个List集合
(2)然后利用迭代器和增强for循环分别遍历集合元素并输出
(3)如:15 18 20 40 46 60 65 70 75 91
需求分析:
随机生成10个1至100之间的不重复整数,可以通过使用Java的Random类,生成随机数,再判断是否已经存在于集合中,如果存在则重新生成。
存储生成的随机数可以使用Java的List集合,因为它能够按照插入顺序存储元素。
遍历集合元素可以使用Java的迭代器和增强for循环。迭代器是遍历集合的标准方法,它能够对集合中的元素进行读取、删除和修改操作。增强for循环是一种简化版的迭代器,它可以遍历集合中的元素,但不能进行修改和删除操作。
输出集合元素可以使用Java的System.out.println方法,将每个元素输出到控制台。

import java.util.*;

public class RandomNumbers {
    public static void main(String[] args) {
        List<Integer> numbers = new ArrayList<>();
        Random rand = new Random();

        // 生成10个1至100之间的不重复整数
        while (numbers.size() < 10) {
            int n = rand.nextInt(100) + 1;
            if (!numbers.contains(n)) {
                numbers.add(n);
            }
        }

        // 使用迭代器遍历集合并输出
        System.out.print("使用迭代器遍历集合:");
        Iterator<Integer> iterator = numbers.iterator();
        while (iterator.hasNext()) {
            int n = iterator.next();
            System.out.print(n + " ");
        }
        System.out.println();

        // 使用增强for循环遍历集合并输出
        System.out.print("使用增强for循环遍历集合:");
        for (int n : numbers) {
            System.out.print(n + " ");
        }
        System.out.println();
    }
}

利用迭代器遍历集合并输出
63 82 15 69 9 87 52 92 93 40 
利用for增强遍历集合并输出
63 82 15 69 9 87 52 92 93 40 

2、
分析以下需求,并用代码实现
(1)定义List集合,存入多个字符串
(2)删除集合元素字符串中包含0-9数字的字符串(只要字符串中包含0-9中的任意一个数字就需要删除此整个字符串)
(3)然后利用迭代器遍历集合元素并输出

package CollectionDemo.Test;

import java.util.*;
import java.util.List;
/*分析以下需求,并用代码实现
    (1)定义List集合,存入多个字符串
    (2)删除集合元素字符串中包含0-9数字的字符串(只要字符串中包含0-9中的任意一个数字就需要删除此整个字符串)
    (3)然后利用迭代器遍历集合元素并输出*/
public class Test2 {
    public static void main(String[] args) {
//        定义List集合,存入多个字符串
        List<String> list = new ArrayList<>();
            list.add("abc");
            list.add("efg");
        Iterator<String> iterator = list.iterator();
        while (iterator.hasNext()){
            String s = iterator.next();
//      (2)删除集合元素字符串中包含0-9数字的字符串(只要字符串中包含0-9中的任意一个数字就需要删除此整个字符串)
            if (s.matches(".*[0-9].*")){
                iterator.remove();
            }
        }
//        (3)然后利用迭代器遍历集合元素并输出
        for (String s:list
             ) {
            System.out.println(s);
        }
    }
}
abc
efg

分析以下需求,并用代码实现
(1)定义Person类包含姓名:String name、年龄:int age、成绩:int score,生成空参、有参构造、set和get方法、toString方法
(2)定义Student类继承Person,属性与Person类相同
(3)查看API中ArrayList集合中的以下方法:
(a)boolean add(E e) 方法
(b) T[] toArray(T[] a)方法
(c)boolean addAll(Collection c)方法
(4)通过查看API对以上方法的学习,完成以下功能
a. ArrayList集合中存入5个Student对象,将ArrayList集合转成对应的数组Studentp[],并遍历打印数组中的元素
b. 定义一个存储Person对象的ArrayList集合对象list1,并出入2个Person对象,定义一个存储Student对象的ArrayList集合对象list2,并出入2个Student对象,
调用addAll方法将list2的全部内容添加到list1中,遍历打印list1中的内容

package CollectionDemo.Test;

import java.util.ArrayList;

/*分析以下需求,并用代码实现
    (1)定义Person类包含姓名:String name、年龄:int age、成绩:int score,生成空参、有参构造、set和get方法、toString方法
    (2)定义Student类继承Person,属性与Person类相同
    (3)查看API中ArrayList集合中的以下方法:
        (a)boolean add(E e) 方法
        (b) T[] toArray(T[] a)方法
        (c)boolean addAll(Collection c)方法
    (4)通过查看API对以上方法的学习,完成以下功能
        a. ArrayList集合中存入5个Student对象,将ArrayList集合转成对应的数组Studentp[],并遍历打印数组中的元素
        b. 定义一个存储Person对象的ArrayList集合对象list1,并出入2个Person对象,定义一个存储Student对象的ArrayList集合对象list2,并出入2个Student对象,
	   调用addAll方法将list2的全部内容添加到list1中,遍历打印list1中的内容*/
public class Test3 {
    public static void main(String[] args) {
        // a. ArrayList集合中存入5个Student对象,将ArrayList集合转成对应的数组Studentp[],并遍历打印数组中的元素
        ArrayList<Person.Student> arrayList = new ArrayList<Person.Student>();
        arrayList.add(new Person.Student("小结",16,79));
        arrayList.add(new Person.Student("小结2",13,45));
        //b. 定义一个存储Person对象的ArrayList集合对象list1,并出入2个Person对象,定义一个存储Student对象的ArrayList集合对象  
        Person.Student[] stu = arrayList.toArray(new Person.Student[arrayList.size()]);
        for (Person.Student st:stu
             ) {
            System.out.println(st);
        }
    }
}
//(1)定义Person类包含姓名:String name、年龄:int age、成绩:int score,生成空参、有参构造、set和get方法、toString方法
class Person{
    String name;
    int age;
    int score;
//    空参构造
    public Person() {

    }
    //    有参构造
    public Person(String name, int age, int score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
//set和get方法
    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 int getScore() {
        return score;
    }

    public void setScore(int score) {
        this.score = score;
    }
    public String toString(){
        return "Person{"+"name="+name+'\''+",age="+age+
                ",score="+score+"}";
    }
    //    (2)定义Student类继承Person,属性与Person类相同
    static class Student extends Person{

    public Student(String name, int age, int score) {
        super(name, age, score);
    }
}
}

4.现在已知Cloth ,衣物都有颜色,价格,牌子;
已知裤子是衣物的一种,裤子有裤袋;
已知袜子也是一种,袜子有个洞;
已知衬衣也是衣服的一种,衬衣有扣子;
已知鞋子也是衣物,鞋子有鞋带
已知人这个类, 人类有姓名,性别, 可以穿衣服;

要求: 定义一个衣柜(衣柜不用创建对象, 里面放置一套衣服);
创建人对象,然后实现穿一套衣服的过程;

package CollectionDemo.Test;
/*现在已知Cloth ,衣物都有颜色,价格,牌子;
  已知裤子是衣物的一种,裤子有裤袋;
  已知袜子也是一种,袜子有个洞;
  已知衬衣也是衣服的一种,衬衣有扣子;
  已知鞋子也是衣物,鞋子有鞋带
  已知人这个类, 人类有姓名,性别, 可以穿衣服;

  要求: 定义一个衣柜(衣柜不用创建对象, 里面放置一套衣服);
        创建人对象,然后实现穿一套衣服的过程;*/
public class Test4 {
    public static void main(String[] args) {
        Person1 person1 = new Person1();
        person1.name="Mary";
        person1.gender = "female";
        Wardrobe wardrobe = new Wardrobe();
        person1.wear(wardrobe.pants);
        person1.wear(wardrobe.socks);
        person1.wear(wardrobe.shirt);
        person1.wear(wardrobe.shoes);
    }
}
class Cloth{
    String color;
    double price;
    String brand;
}
class Pants extends Cloth{
    boolean hasPocket;  //有口袋
}
class Socks extends Cloth{
    boolean hasHole;
}
class Shirt extends Cloth{
    boolean hasButton;
}
class Shoes extends Cloth{
    boolean hasLaces;
}
class Person1 {
    String name;
    String gender;

    void wear(Cloth cloth) {
        System.out.println(name + " is wearing " + cloth.brand + " " + cloth.getClass().getSimpleName() + ".");
    }
}
class Wardrobe{
    Pants pants = new Pants();
    Socks socks = new Socks();
    Shirt shirt =new Shirt();
    Shoes shoes = new Shoes();
    Wardrobe(){
        pants.color="blue";
        pants.price=36.88;
        pants.brand="LOV";
        pants.hasPocket=true;

        socks.color = "white";
        socks.price = 4.99;
        socks.brand = "Hanes";
        socks.hasHole = true;

        shirt.color = "pink";
        shirt.price = 39.99;
        shirt.brand = "Ralph Lauren";
        shirt.hasButton = true;

        shoes.color = "black";
        shoes.price = 79.99;
        shoes.brand = "Nike";
        shoes.hasLaces = true;
    }
}
Mary is wearing LOV Pants.
Mary is wearing Hanes Socks.
Mary is wearing Ralph Lauren Shirt.
Mary is wearing Nike Shoes.

键盘录入若干个字符串,将字符串存入泛型为String的集合当中, 知道输入quit的时候不用输入;
1.集合中含有字符a的元素有多少个
2.将集合中第三个元素中"a"全部替换成"b";
3.删掉长度为3的元素;
4.遍历集合;

package CollectionDemo.Test;

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

/*键盘录入若干个字符串,将字符串存入泛型为String的集合当中, 直到输入quit的时候不用输入;
 1.集合中含有字符a的元素有多少个
 2.将集合中第三个元素中"a"全部替换成"b";
 3.删掉长度为3的元素;
 4.遍历集合;*/
public class Test5 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArrayList<String> stringList = new ArrayList<>(); // 创建泛型为String的ArrayList
        System.out.println("请输入字符串(输入quit结束输入):");
        // 用循环读取用户输入的字符串并存入ArrayList,直到输入"quit"为止
        while (true) {

            String input = scanner.nextLine();
            if (input.equals("quit")) {
                break;
            } else {
                stringList.add(input);
            }
        }

        // 打印集合中含有字符a的元素数量
        int count = 0;
        for (String str : stringList) {
            if (str.contains("a")) {
                count++;
            }
        }
        System.out.println("集合中含有字符a的元素数量为:" + count);

        // 将集合中第三个元素中"a"全部替换成"b"
        if (stringList.size() >= 3) { // 确保集合中至少有3个元素
            String thirdElement = stringList.get(2);
            stringList.set(2, thirdElement.replace("a", "b"));
        }

        // 删除长度为3的元素
        stringList.removeIf(str -> str.length() == 3);

        // 遍历集合并打印每个元素
        System.out.println("遍历集合:");
        for (String str : stringList) {
            System.out.println(str);
        }
    }
}

请输入字符串(输入quit结束输入):
sdha 
jkhg
ghsa
quit
集合中含有字符a的元素数量为:2
遍历集合:
sdha 
jkhg
ghsb

第十八章 Set与Map集合

Set

  • 定义
    在Java中,Set是一种集合类型,它继承自Collection接口,用于存储不重复的元素。Set接口的定义如下:
public interface Set<E> extends Collection<E> {
    // 声明Set特有的方法
}

常用的Set实现类有HashSet、TreeSet和LinkedHashSet。
需要注意的是,Set接口是一个抽象接口,不能直接实例化。需要使用Set接口的实现类来创建Set对象。

  • 特点
    • 无序
    • 不重复
    • 没有整数索引
      java从零开始系统性学习完整超全资源+笔记(下)_第9张图片
  • 方法
    add() toArray()
    java从零开始系统性学习完整超全资源+笔记(下)_第10张图片

增强for循环

增强for循环语法(也称为for-each循环)是Java中用于遍历数组或集合的简化循环语法。其语法形式如下:

for (elementType element : collection) {
    // 循环体
}

其中:
elementType 是集合中元素的类型,也可以是数组的元素类型。
element 是循环变量,用于在每次循环迭代中代表集合中的一个元素。
collection 是要遍历的集合或数组。
增强for循环的工作原理是自动迭代集合或数组,并将每个元素依次赋值给循环变量,然后执行循环体中的代码。循环将在集合或数组中的每个元素上执行一次,直到所有元素都被遍历完为止。
需要注意的是,增强for循环只能用于遍历集合或数组,无法用于遍历其他数据结构或自定义对象。
使用HashSet存储字符串并遍历

package mySet;

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

/*使用HashSet存储字符串并遍历
 *
 *	Set的特点:
 *			 无序(存储和读取的顺序可能不一样)
 *			不允许重复
 *			没有整数索引*/
public class hashSetDemo1 {
    public static void main(String[] args) {
//        创建集合
      Set<String> set = new HashSet<>();    //必须要是泛型的
//        添加元素
      set.add("hello");
      set.add("world");
      set.add(null);
        System.out.println(set.add("java"));
        System.out.println(set.add("java"));    //不允许有重复的元素,所以值输出一个java
//        遍历元素
        for(String s : set){
            System.out.println(s);
        }
    }
}
输出
true
false
null
world
java
hello

为啥输出了true和false?
这段代码输出了"true"和"false",以及集合中的元素。

首先,让我们逐行分析代码的执行:

创建HashSet对象并将其赋值给set变量:Set set = new HashSet<>();

创建一个名为set的HashSet集合,其中存储的元素类型为String。
添加元素到集合中:

set.add(“hello”);:向集合中添加字符串"hello"。
set.add(“world”);:向集合中添加字符串"world"。
set.add(null);:向集合中添加一个null元素。
System.out.println(set.add(“java”));:向集合中添加字符串"java",并输出add方法的返回值。因为集合中原本没有"java"这个元素,所以添加成功,返回true,因此输出为"true"。
System.out.println(set.add(“java”));:再次向集合中添加字符串"java",并输出add方法的返回值。因为集合中已经存在"java"这个元素,添加失败,返回false,因此输出为"false"。

遍历集合中的元素:

使用增强for循环遍历集合中的元素。
for(String s : set){…}:对于集合中的每个元素,将其赋值给变量s,并执行循环体中的代码。
循环体中的代码System.out.println(s);将每个元素打印到控制台。

hashSet

  • 定义
    HashSet实现了Set接口,并且还继承了AbstractSet类,同时也实现了Cloneable接口和Serializable接口。它使用哈希表来存储元素,并且允许存储null元素(只能存储一个)。
    java从零开始系统性学习完整超全资源+笔记(下)_第11张图片

  • 特点

    • 不允许重复元素:HashSet中不会包含重复的元素。当向HashSet中添加元素时,会先通过元素的hashCode()方法计算哈希值,然后根据哈希值确定元素在内部存储结构中的位置。如果发现该位置已经存在元素,则进行比较,如果元素已经存在,则不会添加;如果元素不存在,则将其添加到该位置。
    • 无序性:HashSet中的元素没有特定的顺序。HashSet不会保持元素的插入顺序,也不会按照元素的排序顺序存储。
    • 高效的查找和插入操作:HashSet基于哈希表实现,因此查找和插入操作的性能非常高效,具有常数时间复杂度O(1)。
      可以存储null元素:HashSet可以存储一个null元素,但不能存储多个null元素,因为HashSet要求元素唯一。
    • 不是线程安全的:HashSet不是线程安全的,如果多个线程同时访问一个HashSet并且至少有一个线程修改了集合,则必须进行外部同步。
      遍历性能较好:由于HashSet使用哈希表实现,遍历HashSet的性能较好。
      注意:由于HashSet使用哈希表实现,元素的顺序是根据哈希值决定的,因此无法保证HashSet的元素顺序是固定的。如果需要有序的集合,可以使用LinkedHashSet,它在HashSet的基础上使用了链表来维护元素的插入顺序。
  • add()
    HashSet的add()方法,首先会使用当前集合中的每一个元素和新添加的元素进行hash值比较,
    如果hash值不一样,则直接添加新的元素
    如果hash值一样,比较地址值或者使用equals方法进行比较
    比较结果一样,则认为是重复不添加
    所有的比较结果都不一样则添加

  • 方法
    java从零开始系统性学习完整超全资源+笔记(下)_第12张图片

方法重载与重写

方法重写与方法重载区别
方法重写@override 在子类当中,子类和父类的方法完全一样,子类覆盖了父类的方法,重写之后,使用子类对象调用的就是子类的方法。
方法重载@overload 在一个类中有多个重名方法,但是方法参数不同(参数类型、数目,顺序),和返回值无关。

使用HashSet存储自定义对象并遍历

package mySet;

import java.util.HashSet;

/*
 *	使用HashSet存储自定义对象并遍历
 *
 *	HashSet的add()方法,首先会使用当前集合中的每一个元素和新添加的元素进行hash值比较,
 *	如果hash值不一样,则直接添加新的元素
 *	如果hash值一样,比较地址值或者使用equals方法进行比较
 *	比较结果一样,则认为是重复不添加
 *	所有的比较结果都不一样则添加

 */
public class hashSetDemo2 {
    public static void main(String[] args) {
//    创建集合对象
        HashSet<Student> hashSet = new HashSet<Student>();
//        创建元素对象
        Student s = new Student("张三",18);
        Student s2 = new Student("lisi",18);
        Student s3 = new Student("lisi",18);
//        添加元素
        hashSet.add(s);
        hashSet.add(s2);
        hashSet.add(s3);
//        遍历集合对象 自定义的类
        for (Student student:hashSet
             ) {
            System.out.println(student);
        }
    }
}

class Student {
    String name;
    int age;

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

    @Override
    public String toString() {
        return "Student [name=" + name + ", age=" + age + "]";
    }


    @Override
    public boolean equals(Object obj) {
        System.out.println("-------------------");
        Student s = (Student)obj;//向下转型,可以获取子类特有成员

        //比较年龄是否相等,如果不等则返回false
        if(this.age != s.age) {
            return false;
        }

        //比较姓名是否相等,如果不等则返回false
        if(!this.name.equals(s.name)) {
            return false;
        }

        //默认返回true,说明两个学生是相等的
        return true;
    }

    @Override
    public int hashCode() {
        return 1;
    }
}

hashCode方法和equals方法的优化

我们发现当hashCode方法永远返回整数1时,所有对象的hash值都是一样的, 有一些对象的成员变量完全不同,但是它们还需要进行hash和equals方法的比较,如果我们可以让成员变量不同的对象,它们的hash值也不同,这就可以减少一部分equals方法的比较从而可以提高我们程序的效率

	  可以尝试着让hashCode方法的返回值和对象的成员变量有关
	  可以让hashCode方法返回所有成员变量之和,
	  让基本数据类型直接相加,然后引用数据类型获取hashCode方法返回值后再相加(boolean不可以参与运算)

package mySet;

import java.util.HashSet;

public class HashSetDemo3 {
	public static void main(String[] args) {
		//创建集合对象
		HashSet<Person> hs = new HashSet<Person>();
		//创建元素对象
		Person p = new Person("zhangsan",18);
		Person p2 = new Person("lisi",21);
		Person p3 = new Person("lisi",20);
		//添加元素对象
		hs.add(p);
		hs.add(p2);
		hs.add(p3);
		//遍历集合对象
		for (Person person : hs) {
			System.out.println(person);
		}
		
	}
}

Person.java

package com.demo02;

public class Person {
	String name;
	int age;
	
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
//自动生成的方法重写
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + "]";
	}

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

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Person other = (Person) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
	
	
	
	/*	自己写的
	@Override
	public int hashCode() {	 
		//return age;
		return age + name.hashCode();
	}
	
	@Override
	public boolean equals(Object obj) {
		System.out.println("-------------");
		
		//提高效率
		if(this == obj) {
			return true;
		}
		
		//提高健壮性
		if(this.getClass() != obj.getClass()) {
			return false;
		}
		
		
		
		//向下转型
		Person p = (Person)obj;
		
		if(!this.name.equals(p.name)) {
			return false;
		}
		
		if(this.age != p.age) {
			return false;
		}
		
		return true;
		
	}
	*/
	
	
}

Collection

定义

Collection 层次结构 中的根接口。Collection 表示一组对象,这些对象也称为 collection 的元素。一些 collection 允许有重复的元素,而另一些则不允许。一些 collection 是有序的,而另一些则是无序的。JDK 不提供此接口的任何直接 实现:它提供更具体的子接口(如 Set 和 List)实现。此接口通常用来传递 collection,并在需要最大普遍性的地方操作这些 collection。
Collections:

Collection和Collections有什么区别?

面试题:Collection和Collections有什么区别?

Collection是集合体系的最顶层,包含了集合体系的共性
Collections是一个工具类,方法都是用于操作Collection
java从零开始系统性学习完整超全资源+笔记(下)_第13张图片

  • Collection
    java从零开始系统性学习完整超全资源+笔记(下)_第14张图片
collection方法

java从零开始系统性学习完整超全资源+笔记(下)_第15张图片

  • static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换
  • static int binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置 1 2 3 4 5 6 7
  • static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表
    注意:目标列表的长度至少等于源列表的长度
  • static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素
  • static void reverse(List list) :反转
  • static void sort(List list) :按照列表中元素的自然顺序进行排序
public class CollectionsDemo {
	public static void main(String[] args) {
		method7();
	
	}

	private static void method7() {
		//static void swap(List list, int i, int j) :将指定列表中的两个索引进行位置互换
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(7);
		list.add(0);
		list.add(-1);
		System.out.println(list);
		Collections.swap(list, 2, 5);
		System.out.println(list);
		
	}

	private static void method() {
		//static int  binarySearch(List list, Object key) 使用二分查找法查找指定元素在指定列表的索引位置 1 2 3 4 5 6 7
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		list.add(5);
		list.add(6);
		list.add(7);
		
		int index = Collections.binarySearch(list, 4);
		System.out.println(index);
	}
	

	private static void method2() {
		//static void copy(List dest, List src) :是把源列表中的数据覆盖到目标列表
		//注意:目标列表的长度至少等于源列表的长度
		//创建源列表
		List<String> src = new ArrayList<String>();
		src.add("hello");
		src.add("world");
		src.add("java");
		
		//创建目标列表
		List<String> dest = new ArrayList<String>();
		dest.add("java");
		dest.add("java");
		//dest.add("java");
		//dest.add("java");
		Collections.copy(dest, src);
		System.out.println(dest);
	}

	
	private static void method3() {
		//static void fill(List list, Object obj) :使用指定的对象填充指定列表的所有元素
		List<String> list = new ArrayList<String>();
		list.add("hello");
		list.add("world");
		list.add("java");
		System.out.println(list);
		
		Collections.fill(list, "android");
		
		System.out.println(list);
	}

	private static void method4() {
		//static void reverse(List list)  :反转
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		System.out.println(list);
		Collections.reverse(list);
		System.out.println(list);
	}

	private static void method5() {
		//static void shuffle(List list):傻否,随机置换  
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(2);
		list.add(3);
		list.add(4);
		System.out.println(list);
		Collections.shuffle(list);
		System.out.println(list);
	}

	private static void method6() {
		//static void  sort(List list) :按照列表中元素的自然顺序进行排序
		List<Integer> list = new ArrayList<Integer>();
		list.add(1);
		list.add(4);
		list.add(3);
		list.add(2);
		System.out.println(list);
		Collections.sort(list);
		System.out.println(list);
	}	
}
输出:
[1, 2, 3, 4, 7, 0, -1]
[1, 2, 0, 4, 7, 3, -1]

Collection练习 模拟斗地主

package com.demo03;

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

/*
 *	模拟斗地主发牌 
 	
 	买牌
 	洗牌
 	发牌
 
 */
public class CollectionsTest {
	public static void main(String[] args) {
		//String[] box0 = {"黑桃A","黑桃2"...}
		//买牌
		String[] arr = { "黑桃", "红桃", "方片", "梅花" };
		String[] arr2 = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K" };

		ArrayList<String> box = new ArrayList<String>();
		//添加每张牌
		for (int i = 0; i < arr.length; i++) {
			//获取每一个花色
			for (int j = 0; j < arr2.length; j++) {
				//获取每一个数
				box.add(arr[i] + arr2[j]);
			}

		}
		box.add("大王");
		box.add("小王");
		System.out.println(box.size());
		System.out.println(box);
		
		//洗牌
		Collections.shuffle(box);
		System.out.println(box);
		
		//发牌
		ArrayList<String> 林志玲 = new ArrayList<String>();
		ArrayList<String> 林心如 = new ArrayList<String>();
		ArrayList<String> 舒淇 = new ArrayList<String>();
		
		//留三张底牌给地主
		for (int i = 0; i < box.size() - 3; i++) {
			
			/*	   i = 0;i % 3 = 0;
				   i = 1;i % 3 = 1;
				   i = 2;i % 3 = 2;
				   i = 3;i % 3 = 0;
				   i = 4;i % 4 = 1;
				   i = 5;i % 5 = 2;*/
			 
			
			if(i % 3 == 0) {
				林志玲.add(box.get(i));
			}else if(i % 3 == 1) {
				林心如.add(box.get(i));
			}else if(i % 3 == 2) {
				舒淇.add(box.get(i));
			}
		}
		
		System.out.println("林志玲:" + 林志玲);
		System.out.println("林心如:" + 林心如);
		System.out.println("舒淇:" + 舒淇);
		
		
		System.out.println("底牌:");
		/*System.out.println(box.get(box.size() - 1));
		System.out.println(box.get(box.size() - 2));
		System.out.println(box.get(box.size() - 3));*/
		
		for (int i = box.size() - 3; i < box.size(); i++) {
			System.out.println(box.get(i));
		}
	}

}
54
[黑桃A, 黑桃2, 黑桃3, 黑桃4, 黑桃5, 黑桃6, 黑桃7, 黑桃8, 黑桃9, 黑桃10, 黑桃J, 黑桃Q, 黑桃K, 方块A, 方块2, 方块3, 方块4, 方块5, 方块6, 方块7, 方块8, 方块9, 方块10, 方块J, 方块Q, 方块K, 红桃A, 红桃2, 红桃3, 红桃4, 红桃5, 红桃6, 红桃7, 红桃8, 红桃9, 红桃10, 红桃J, 红桃Q, 红桃K, 梅花A, 梅花2, 梅花3, 梅花4, 梅花5, 梅花6, 梅花7, 梅花8, 梅花9, 梅花10, 梅花J, 梅花Q, 梅花K, 大王, 小王]
[红桃7, 梅花J, 梅花4, 黑桃4, 大王, 方块2, 梅花2, 黑桃6, 方块7, 方块3, 方块Q, 黑桃A, 黑桃3, 梅花8, 红桃8, 红桃10, 梅花10, 黑桃10, 红桃A, 红桃K, 黑桃9, 方块A, 梅花Q, 梅花5, 红桃6, 黑桃7, 梅花A, 红桃5, 红桃4, 红桃2, 方块4, 方块10, 方块8, 方块K, 黑桃5, 方块6, 方块J, 红桃Q, 梅花6, 红桃J, 黑桃J, 红桃3, 方块9, 梅花7, 方块5, 黑桃K, 梅花K, 红桃9, 小王, 黑桃Q, 黑桃8, 黑桃2, 梅花9, 梅花3]
林志玲[红桃7, 黑桃4, 梅花2, 方块3, 黑桃3, 红桃10, 红桃A, 方块A, 红桃6, 红桃5, 方块4, 方块K, 方块J, 红桃J, 方块9, 黑桃K, 小王]
林心如[梅花J, 大王, 黑桃6, 方块Q, 梅花8, 梅花10, 红桃K, 梅花Q, 黑桃7, 红桃4, 方块10, 黑桃5, 红桃Q, 黑桃J, 梅花7, 梅花K, 黑桃Q]
舒淇[梅花4, 方块2, 方块7, 黑桃A, 红桃8, 黑桃10, 黑桃9, 梅花5, 梅花A, 红桃2, 方块8, 方块6, 梅花6, 红桃3, 方块5, 红桃9, 黑桃8]
底牌:
黑桃2
梅花9
梅花3

Map

需求:实现学号和姓名这样有对应关系的数据存储

  • 为了体现这种有对应关系的数据,我们使用以前所学的内容是可以实现的,但是略有不便,所以java又给我们提供了一种专门用于存储对应关系的集合。
    Map:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值
Map和Collection有什么区别?

Map:是一个双列集合,常用语处理有对应关系的数据,key是不可以重复的,我们也称之为是夫妻对集合
Collection:是单列集合,Collection有不同的子体系,有的允许重复有索引有序,有的不允许重复而且无序,那么我们也称之为单身汉集合
一对一:一个学号对应一个姓名。
定义:将键映射到值的对象。一个映射不能包含重复的键;每个键最多只能映射到一个值。

map常用功能

映射功能:
V put(K key, V value)
获取功能:
V get(Object key)
int size()
判断功能:
boolean containsKey(Object key)
boolean containsValue(Object value)
boolean isEmpty()
删除功能:
void clear()
V remove(Object key)
遍历功能:
Set> entrySet()

  •  	Set keySet()  
    
  •  	Collection values()  
    
public class MapDemo2 {
	public static void main(String[] args) {
		//创建Map对象
		Map<String,String> map = new HashMap<String,String>();
		
		//V put(K key, V value) :就是将key映射到value,如果key存在,则覆盖value,并将原来的value返回
		System.out.println(map);
		System.out.println(map.put("s001", "张三"));
		System.out.println(map.put("s002", "李四"));
		System.out.println(map.put("s001", "王五"));
		//System.out.println(map.put("s001", null));
		System.out.println(map);
		//V get(Object key) : 根据指定的key返回对应的value
		//System.out.println(map.get("s002"));
		//System.out.println(map.get("s002sdf"));

		//int size() : 返回对应关系的个数
		//System.out.println(map.size());
		//boolean containsKey(Object key) : 判断指定key是否存在
		//System.out.println(map.containsKey("s003"));
		//System.out.println(map.containsKey("s002"));
		
		//boolean containsValue(Object value):判断指定的value是否存在
		//System.out.println(map.containsValue("王五"));
		//System.out.println(map.containsValue("王"));
				
		
		//void clear() : 清空所有的对应关系  
		//map.clear();
		//System.out.println(map);
		//V remove(Object key) :根据指定的key删除对应关系,并返回key所对应的值,如果没有删除成功则返回null
		System.out.println(map.remove("s005"));
		System.out.println(map.remove("s002"));
		System.out.println(map);
		
		//boolean isEmpty() : 判断是否有对应关系
		System.out.println(map.isEmpty());
		map.clear();
		System.out.println(map);
		System.out.println(map.isEmpty());
	}
}

Set keySet() 获取map的键,Collection values() 获取map的值

/*
 * 	Set keySet()  
 * 	Collection values() 
 */
public class MapDemo3 {
	public static void main(String[] args) {
		//创建Map对象
		Map<String,String> map = new HashMap<String,String>();
		//添加映射关系
		map.put("s001", "张三");
		map.put("s002", "李四");
		map.put("s005", "李四");
		
		//Set keySet() : 以Set的形式获返回所有的key
		Set<String> keys = map.keySet();
		for (String key : keys) {
			System.out.println(key);
		}
		
		System.out.println("-----------");
		
		//Collection values() :
		Collection<String> values = map.values();
		for (String value : values) {
			System.out.println(value);
		}
		
		
	}
}

s005
s002
s001
-----------
李四
李四
张三
map的两种遍历方式
  • map的第一种遍历方式
    首先召集所有的键(丈夫):
Set<String> keys = map.keySet();

遍历所有的键(丈夫):

for (String key : keys) {
			//让每个丈夫去找他自己的媳妇就可以了
			String value = map.get(key);
			System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
}			

获取每一个键(丈夫)
让每一个键(丈夫)去找他自己的值(媳妇)

/*
 * 	Map的第一种遍历方式:
 * 			首先召集所有的丈夫
 * 			遍历所有的丈夫
 * 			获取每一个丈夫
 * 			让每一个丈夫去找他自己的媳妇
 */
public class MapDemo4 {
	public static void main(String[] args) {
		//创建Map对象
		Map<String,String> map = new HashMap<String,String>();
		//添加映射关系
		map.put("谢婷疯", "张箔纸");
		map.put("陈关西", "钟欣桶");
		map.put("李亚碰", "王飞");
		//遍历Map对象
		
		//首先召集所有的丈夫
		Set<String> keys = map.keySet();
		//遍历所有的丈夫
		for (String key : keys) {
			//让每个丈夫去找他自己的媳妇就可以了
			String value = map.get(key);
			System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
		}
		
	}
}
Map的第二种遍历方式

通过结婚证对象来获取丈夫和媳妇

for (Map.Entry<String, String> entry : entrys) {
			//获取每个单独的结婚证对象
			//通过结婚证对象获取丈夫和媳妇
			String key = entry.getKey();
			String value = entry.getValue();	
			System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
		}
 Set<Map.Entry<K,V>> entrySet()  
/*
 * 	Map的第二种遍历方式:
 * 		通过结婚证对象来获取丈夫和媳妇
 *  Set> entrySet()  
 * 
 */
public class MapDemo5 {
	public static void main(String[] args) {
		//创建Map对象
		Map<String,String> map = new HashMap<String,String>();
		//添加映射关系
		map.put("尹志平", "小龙女");
		map.put("令狐冲", "东方姑娘");
		map.put("玄慈", "叶二娘");
		//获取所有的结婚证对象
		Set<Map.Entry<String,String>> entrys = map.entrySet();
		//遍历包含了结婚证对象的集合
		for (Map.Entry<String, String> entry : entrys) {
			//获取每个单独的结婚证对象
			//通过结婚证对象获取丈夫和媳妇
			String key = entry.getKey();
			String value = entry.getValue();
			
			System.out.println("丈夫:" + key + "---" + "媳妇:" + value);
		}
		
	}
}
使用HashMap存储数据并遍历(字符串作为key)
package com.demo02;

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

/*
 * 
 * 使用HashMap存储数据并遍历(字符串作为key)
 * 
 */
public class HashMapDemo {
	public static void main(String[] args) {
		//创建Map对象
		HashMap<String,String> hm = new HashMap<String,String>();
		//添加映射关系
		hm.put("s001", "张三");
		hm.put("s002", "李四");
		hm.put("s003", "王五");
		hm.put("s003", "赵六");
		//遍历Map对象
		
		//方式1 获取所有的key,通过key来获取value
		Set<String> keys = hm.keySet();
		for (String key : keys) {
			String value = hm.get(key);
			System.out.println(key + "=" + value);
		}
		
		System.out.println("------------------");
		
		//方式2:获取所有的结婚证对象,然后通过结婚证对象获取丈夫和媳妇
		Set<Map.Entry<String, String>> entrys = hm.entrySet();
		for (Map.Entry<String, String> entry : entrys) {
			String key = entry.getKey();
			String value = entry.getValue();
			System.out.println(key + "=" + value);
		}
	}
}

使用HashMap存储数据并遍历(自定义对象作为key)
package com.demo02;

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

/*
 * 
 * 使用HashMap存储数据并遍历(自定义对象作为key)
 * 
 */
public class HashMapDemo2 {
	public static void main(String[] args) {
		//创建Map对象
		HashMap<Student,String> hm = new HashMap<Student,String>();
		//创建key对象
		Student s = new Student("zhangsan",18);
		Student s2 = new Student("lisi",20);
		Student s3 = new Student("lisi",20);
		
		//添加映射关系
		hm.put(s, "s001");
		hm.put(s2, "s002");
		hm.put(s3, "s002");
		
		//遍历Map对象
		//方式1: 获取所有的key,通过key来获取value
		Set<Student> keys = hm.keySet();
		for (Student key : keys) {
			String value = hm.get(key);
			System.out.println(key + "=" + value);
		}
		System.out.println("-----");
		
		//方式2:获取所有结婚证对象,通过结婚证对象获取丈夫和媳妇
		Set<Map.Entry<Student, String>> entrys = hm.entrySet();
		for (Entry<Student, String> entry : entrys) {
			Student key = entry.getKey();
			String value = entry.getValue();
			
			System.out.println(key + "=" + value);
		}
		
	}
}

Student类

package com.demo02;

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

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + "]";
	}

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

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}	
}

第十九章 异常的处理

异常的概述和体系结构.

  • Exception in thread “main” java.lang.ArithmeticException: / by zero
    at com.demo01.ExceptionDemo.main(ExceptionDemo.java:5)
    我们在写代码的时候,经常的出现一些小问题,那么为了方便我们处理这些问题,java为我们提供了异常机制
    异常包含了错误的类型、原因以及位置

    异常:不正常,我们在代码的时候出现的编译或者运行时的错误

    异常的体系结构:
    Throwable(最顶层)
    Error:出现的不能够处理的严重问题
    Exception:可以处理的问题

    电脑坏了:
    系统中毒:重装系统就可以了 这是Exception
    主板坏了:买一台新的 这是Error

什么是异常?举例子:

public class exceptionDemo {
    public static void main(String[] args) {
        int a = 10 / 0;
        System.out.println(a);
    }
}

输出:出现异常
Exception in thread “main” java.lang.ArithmeticException: / by zero
at ExceptionDemo.exceptionDemo.main(exceptionDemo.java:5)
java从零开始系统性学习完整超全资源+笔记(下)_第16张图片
Throwable
java从零开始系统性学习完整超全资源+笔记(下)_第17张图片

JVM处理异常的方式

1.捕获处理
try…catch语句

try…catch的执行顺序:
首先执行try语句如果发现异常,异常下面的代码不再执行,直接跳入catch语句中,catch语句结束后,整个try…catch结束
如果没有发现异常,try语句执行结束后,try…catch直接结束, 不再执行catch语句

 try{
        有可能出现问题的代码;
  }catch(ArithmeticException ae){
        处理异常;
  }

2.抛出去
当我们不想处理异常,或者没有能力处理的时候,我们可以选择抛出异常,谁调用方法谁处理异常
使用关键字throws在方法的声明出抛出异常

jvm处理异常的方式:
如果出现异常我们没有处理,jvm会帮我们进行处理,它会把异常的类型,原因还有位置显示在命令行,并且还终止了程序,异常后面的代码将不在执行。

public class ExceptionDemo2 {
	public static void main(String[] args) throws Exception {
		/*try {
			System.out.println("执行前");
			int a = 10 / 2;
			System.out.println("执行后");
			System.out.println(a);
		}catch(ArithmeticException e) {
			System.out.println("不能除0");
		}
		System.out.println("执行完问题语句后");
		
		*/
		try {
			readFile();
		}catch(FileNotFoundException e) {
			System.out.println("没有发现文件");
		}
		
	}

	public static void readFile() throws FileNotFoundException {
		FileReader fr = new FileReader("d:\\a.txt");
	}
}

如何处理多个异常

可以使用多个try…catch语句
使用一个try和多个catch
多个catch之间的顺序:
多个catch之间可以有子父类
平级之间没有顺序关系
如果有子父类,父类异常必须放在后面

public class ExceptionDemo3 {
	public static void main(String[] args) {
		try {
			String s = "1";
			System.out.println(s.length());

			int[] arr = new int[5];
			System.out.println(arr[4]);
			
			int i = 10;
			System.out.println(i/0);
			
			
		} catch (ArrayIndexOutOfBoundsException e) {
			System.out.println("数组越界异常");
		} catch (NullPointerException e) {
			System.out.println("空指针异常");
		} catch (Exception e) {
			System.out.println("异常");
		}
		
		
	}

}

Throwable的常用方法

Throwable的常用方法:

  • String getMessage() 原因
  • String toString() 类型和原因
  • void printStackTrace() 类型原因和位置
public class exceptionDemo2 {
    public static void main(String[] args) {
        try{
            System.out.println(2 / 0);
        }catch (ArithmeticException e){
//            String getMessage():原因
            System.out.println(e.getMessage());
//          String toString()类型和原因
            System.out.println(e.toString());
//            void printStackTrace():类型原因和位置
            e.printStackTrace();
        }
    }
}

java从零开始系统性学习完整超全资源+笔记(下)_第18张图片

finally概述和应用场景

finally:组合try…catch使用,用于释放资源等收尾工作,无论try…catch语句如何执行,finally的代码一定会执行。

try{
	有可能出现问题的代码;
}catch(异常对象){
	处理异常;
}finally{
	释放资源;
	清理垃圾;
}
package ExceptionDemo;

import java.io.FileWriter;
import java.io.IOException;

public class finallyDemo {
    public static void main(String[] args) {
        FileWriter fileWriter = null;
        try{
            fileWriter = new FileWriter("a.txt");
            fileWriter.write("你好");
            System.out.println(2/0);
            fileWriter.write("我在学java");
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try{
                fileWriter.close();
            }catch (IOException e){
                e.printStackTrace();
            }
        }
    }
}

输出:Exception in thread “main” java.lang.ArithmeticException: / by zero
at ExceptionDemo.finallyDemo.main(finallyDemo.java:12)

异常的分类

异常的分类:
运行时期异常:RuntimeException的子类就是运行时期异常,在编译时期可以自由选择处理或者不处理。RuntimeException 是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类。例如:ArithmeticException(当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。 )
编译时期异常:是Exception的子类,非RuntimeExcpetion的子类,在编译时期必须处理
java从零开始系统性学习完整超全资源+笔记(下)_第19张图片
举例子:

public class exceptionClassification {
    public static void main(String[] args) throws IOException {
       /* System.out.println(2 / 0);
        String s = null;
        System.out.println(s.length());
        运行时异常 输出 ArithmeticException
        */
        FileWriter fw = new FileWriter("a.txt");    
        //编译异常,在编译的时候必须处理,处理方式就是抛出异常
    }
}

自定义异常

自定义异常的方法:写一个类去继承Exception或者RuntimeException,然后实现多个构造即可
1.先自定义异常:写一个类去继承Exception或者RuntimeException

package ExceptionDemo;

public class MyException extends RuntimeException{
    private static final long serialVersionUID = 1L;
    public MyException(){
        super();
    }
    public MyException(String s){
        super(s);
        System.out.println("自定义异常");
    }
}

2.实现多个构造

package ExceptionDemo;

public class exceptionDemo3 {
    public static void main(String[] args) {
    checkScore(110);
    }
    public static void checkScore(int score) throws MyException{
        if(score < 0 || score > 0){
            throw new MyException("考试不符合要求");
        }
        System.out.println("符合要求");
    }
}

输出:
自定义异常
Exception in thread “main” ExceptionDemo.MyException: 考试不符合要求
at ExceptionDemo.exceptionDemo3.checkScore(exceptionDemo3.java:9)
at ExceptionDemo.exceptionDemo3.main(exceptionDemo3.java:5)

递归概述和例题

递归:把大问题拆成很多小问题,然后再把小问题拆成更多的小问题,
当我们把更多小问题解决了,小问题也解决了
随着小问题的解决,大问题也随之解决了
在方法本身不断的调用方法自己

递归注意事项:
		==递归一定要有出口,内存溢出==
		==递归次数不宜过多,内存溢出==
package Recurrence;
/*
 * 需求:求5的阶乘
 * 5! = 5 * 4 * 3 * 2 * 1;  //120
 * 5! = 5 * 4!;					//120
 * 		4! = 4 * 3!;			//24
 * 			3! = 3 * 2!;		//6
 * 				2! = 2 * 1!;	//2
 * 					1! = 1;     //1
	n! = n * (n - 1)!
 */
public class recurrenceDemo1 {
    public static void main(String[] args) {
        int n = method(5);
        System.out.println(n);
    }
    public static int method(int n){
        if(n == 0){ //出口
            return 1;
        }else{
            return n * method(n-1);
        }
    }
}

斐波那契数列:

package Recurrence;
/*
 * 古典问题:有一对兔子,从出生后第3个月起每个月都生一对兔子,
 * 		     小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,
 *  	     问第二十个月的兔子对数为多少?
 *  1
 *  1
 *  2
 *  3
 *  5
 *  8
 *  13

 *  规律:除了第一个月和第二月以外,其余每个月都是前两个月之和
 *  斐波那契列数
 *
 */
public class recurrentDemo2 {
    public static void main(String[] args) {
        int m = method(20);
        System.out.println(m);
    }
    public static int method(int n){
        if(n == 1){
            return 1;
        }else if(n==2){
            return 1;
        }else{
            return method(n-1)+method(n-2);
        }
    }
}

练习:手动实现FileWriter的try catch异常处理形式的完整模式

package ExceptionDemo;

import java.io.FileWriter;
import java.io.IOException;

/*手动实现FileWriter的try catch异常处理形式的完整模式*/
public class exceptionTest {
    public static void main(String[] args) throws IOException {
       demo();
    }
    private static void demo(){
        FileWriter fileWriter = null;
        try{
            fileWriter = new FileWriter("E://a.txt");
            fileWriter.write("小猫");
            fileWriter.write("小狗");
        }catch(Exception e){
            System.out.println("出现异常");
            e.printStackTrace();
        }finally {
            try {
                if(fileWriter!=null){
                    fileWriter.close();
                }
            }catch(IOException el){
                el.printStackTrace();
            }
        }
    }
    public static int get(){
        try{
            return 520;
        }finally {
            System.out.println("发生异常");
        }
    }
}


第二十章 多线程

线程概述

进程

进程相当于公司,多线程相当于公司的多个程序员。

线程

单线程特点:安全性高,一件事交给一个人干,确定性的知道干到哪里了。但是效率低
多线程特点: 安全性低因为一个人干一部分,需要对接,每个人的写法不一样,对接出现问题,一个人的错误导致整体的问题。但是效率高
例如:杀毒软件同时做多件事情,电脑体检、木马查杀、电脑清理等。在这里插入图片描述

多线程的实现

1.新建一个类,并将类声明为Thread的子类,该子类应该重写thread类的run方法。

package Thread;
//标准的多线程实现的类
public class MyThread extends Thread{
    @Override
    public void run(){
        for (int i = 0; i < 100; i++) {
            System.out.println(i);
        }
    }
}

2.创建多线程实例

public class ThreadDemo1 {
    public static void main(String[] args) {
//        创建线程实例 声明实例
        MyThread t = new MyThread();
//        启动多线程
        t.run();    //执行一次 输出0-99,t.run和普通的方法一样,所以启动多线程不能用run()

    }
}

输出0-99,t.run和普通的方法一样,所以启动多线程不能用run()

线程相关方法

void setName(String name)
改变线程名称,使之与参数 name 相同。
返回该线程的名称
String getName()

线程安全

你可能感兴趣的:(java系统学习,IDEA,java,学习,jvm)