Java基础一篇就够

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


常用快捷键

Ctrl + D 复制本行代码
Ctrl + X 剪切本行代码
Alt + Shift + 方向键 移动本行代码
Ctrl + Alt + T 在选定代码上,外加代码(分支或循环等等)
Ctrl + Alt + V 补全代码
Shift + F6 直接一次性改名称
Ctrl + Alt + L 格式化数组

IDEA IJ 的一些使用

File–Project Structure–可以修改Module JDK版本

注释

快捷键:Ctrl + / 或 Ctrl + Shift +/

字面量

System.out.println(‘\n’); 代表换行
System.out.println(‘\t’); 代表一个tab

String 接字符串
char 接字符

变量

格式:数据类型 变量名称 = 初始值;

		 数据类型 变量名称; 这是在定义一个变量。     int a;
		 变量名称 = 初始值; 这是在赋值。				a = 10; 

强制类型转换

数据类型 变量1 = (数据类型)变量2;
int a = 20;
byte b = (byte) a;

运算符

取余:%

在Java中,两整数相除结果还是整数,想要有小数位要在变量后*1.0。
在这里插入图片描述

连接运算符 ‘+’

优先从左算起
在这里插入图片描述

自增自减运算符 ‘++’ ‘–’

运算符在变量前:先对变量进行运算,再使用变量。
运算符在变量后:先使用变量,再对变量进行运算。
在这里插入图片描述
在这里插入图片描述

赋值运算符

在这里插入图片描述

关系运算符

在这里插入图片描述

逻辑运算符

在这里插入图片描述

短路逻辑运算符

在这里插入图片描述

三元运算符

在这里插入图片描述

运算符优先等级

在这里插入图片描述

键盘录入技术

在这里插入图片描述

分支

if分支

在这里插入图片描述

switch分支

在这里插入图片描述
表达式类型只能是:byte、short、int、char
case给出的值不允许重复,且只能是字面量,不能是变量。

在这里插入图片描述

switch的穿透性

在这里插入图片描述
在这里插入图片描述

循环结构

知道循环几次用for,不知道循环几次用while。
for循环定义的变量只能在for循环内使用,while循环需要在循环外定义变量。

for循环

在这里插入图片描述
快捷写法:for+i 。

while循环

在这里插入图片描述

do-while循环

在这里插入图片描述

死循环

在这里插入图片描述

嵌套循环

在这里插入图片描述
在这里插入图片描述

跳转关键字

在这里插入图片描述

如果是嵌套循环,想要结束外部循环,要使用break OUT;
在这里插入图片描述

随机数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数组

静态初始化数组

在这里插入图片描述
在这里插入图片描述

动态初始化数组

在这里插入图片描述
在这里插入图片描述

数组的遍历

在这里插入图片描述
快捷键:a.for+i

在这里插入图片描述

数组中的元素交换

要定义临时变量
在这里插入图片描述

方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

方法定义技巧

1.分析方法是否需要申明返回值类型。
2.分析方法是否需要接收参数。

返回数组的方法的定义与调用

在这里插入图片描述

方法参数的传递机制:值传递

基本类型传递的是数据值,如果使用方法时方法改变变量值,但方法使用后,变量值不变。

引用类型传递的是地址值,如果使用方法时方法改变数组数值,方法使用后,数组数值将会改变。

方法重载

同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法。
形参列表不同指的是形参的个数、类型、顺序不同。

return 关键字

在这里插入图片描述
在这里插入图片描述

算法----信号位思想flag

案例:使随机数不重复的方法
在这里插入图片描述

案例:找素数
在这里插入图片描述

面向对象(oop)

设计对象并使用

在这里插入图片描述
在这里插入图片描述

对象在内存中的运行机制

在这里插入图片描述
对象储存在堆内存中
变量名称 c1 储存的是对象在堆内存中的地址
成员变量的数据储存在堆内存中

构造器

在这里插入图片描述

在这里插入图片描述

this关键字

在这里插入图片描述

在这里插入图片描述

this出现在有参数构造器中的用法
在这里插入图片描述

在这里插入图片描述

封装----private

在这里插入图片描述
在这里插入图片描述

封装private
在这里插入图片描述
调用
在这里插入图片描述

标准JavaBean

JavaBean:也可以称为实体类,其对象可以用于在程序中封装数据。

在这里插入图片描述

快捷键

为成员变量提供getter 和setter方法时,快捷写法为直接鼠标右键选中Generate,然后选择Getter and Setter 。
写有参数构造器时,快捷写法为鼠标右键选中Generate,然后选择 Constructor 。
写无参数构造器时,快捷写法为鼠标右键选中Generate,然后选择 Constructor ,再选择 Select None 。

成员变量和局部变量的区别

在这里插入图片描述

API

在这里插入图片描述

String

概述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

创建字符串对象的2种方式

在这里插入图片描述

方式二中常用第三、四种:(如下)
在这里插入图片描述

两种方式的区别
在这里插入图片描述

方式一原理
在这里插入图片描述

方式二原理
在这里插入图片描述

String类常用API

在这里插入图片描述

遍历

方法一:获取某个索引位置处的字符
在这里插入图片描述

方法二:将当前字符串转换成字符数组返回

在这里插入图片描述

截取----substring

方式一:根据开始和结束索引进行截取(包前不包后)。

在这里插入图片描述

方式二:从传入的索引处截取,截取到末尾。

在这里插入图片描述

替换----replace

在这里插入图片描述

分割----split

在这里插入图片描述

String字符串的内容比较----equals

字符串内容比较不能用“==”,因为它比较的是字符串的地址,无法比较内容。
在这里插入图片描述

ArrayList

概述

在这里插入图片描述

ArrayList添加元素的API

在这里插入图片描述

ArrayList的泛型使用

一般使用ArrayList都要使用泛型,这样才更规范。
在这里插入图片描述

ArrayList的常用API

在这里插入图片描述

遍历

使用 get 和 size 。
在这里插入图片描述

ArrayList边遍历边删除元素

在这里插入图片描述
在这里插入图片描述

static

static关键字----可以在任何地方被访问

在这里插入图片描述

修饰成员变量

在这里插入图片描述

在这里插入图片描述

修饰成员方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

注意事项

在这里插入图片描述

static-工具类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

private 类名(){
//工具类私有方法,私有后无法使用该类new对象
    }

static-代码块----面向对象

在这里插入图片描述

在这里插入图片描述

static-单例设计模式

在这里插入图片描述
单例第一步先将构造器私有化

private 类名 (){
}

饿汉单例

先提前创建一个对象

步骤:
在这里插入图片描述

懒汉单例

在真正需要对象的时候,才去创建一个对象(延迟加载对象)
在这里插入图片描述

private 私有静态成员变量,就无法直接调用成员变量。

面向对象----继承----extends

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

继承特点

在这里插入图片描述

子类不可以直接使用父类的私有方法
子类可以使用父类的静态成员变量

在这里插入图片描述

成员变量、成员方法访问特点

在这里插入图片描述

在这里插入图片描述

方法重写----@Override

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

构造器特点

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

public 子类 (){
	super();
	
}

在这里插入图片描述



子类调用父类有参数构造器:

public 子类 (){
	super(父类成员变量,父类成员变量,);
}


在这里插入图片描述

this、super 总结

在这里插入图片描述

在这里插入图片描述

面向对象----语法

在这里插入图片描述

在这里插入图片描述

权限修饰符----public等

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

final

在这里插入图片描述
在这里插入图片描述

常量----public static final

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

枚举–enum

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

抽象类–abstract

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

特征和注意事项

在这里插入图片描述

在这里插入图片描述

模块方法模式

在这里插入图片描述
在这里插入图片描述

接口–interface

在这里插入图片描述
接口会默认公开,所以常量可以省略public static final 不写,抽象方法可以省略public abstract不写。

接口多实现–implement

在这里插入图片描述
在这里插入图片描述

接口多继承

在这里插入图片描述
在这里插入图片描述

接口新增方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

注意事项

在这里插入图片描述

面向对象----多态

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

优势

在这里插入图片描述

在这里插入图片描述

多态下引用数据类型的类型转换

//父类
public class User {
}

//子类
public class Customer extends User{
}

//子类
public class Business extends User {
}
//创建几个对象
User user;
Customer customer;
Business business;

子类对象转为父类类型----自动类型转换

在这里插入图片描述

User user = business;
User user = customer;

父类对象转为子类类型----强制类型转换

在这里插入图片描述

Customer customer = (Customer)user;
Business business = (Business)user;

instanceof----判断当前对象的真实类型

//判断当前父类对象是哪个子类类型
user instanceof Customer

内部类----面向对象

在这里插入图片描述

在这里插入图片描述

静态内部类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

成员内部类

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

局部内部类

在这里插入图片描述

匿名内部类

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

使用形式

在这里插入图片描述

在这里插入图片描述

常用API

Object

在这里插入图片描述

在这里插入图片描述

toString----返回对象内容,而不是返回地址

在这里插入图片描述

快捷键:子类重写直接用Genenrate–toString() 。

@Override
    public String toString() {
        return "Movie{" +
                "name='" + name + '\'' +
                ", score=" + score +
                ", actor='" + actor + '\'' +
                '}';
    }

equals----比较内容是否相同,而不是地址

在这里插入图片描述
子类重写直接用Generate–equals() and hashCode() , 然后去掉hashCode() 。

@Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Movie movie = (Movie) o;
        return Double.compare(movie.score, score) == 0 && Objects.equals(name, movie.name)
         && Objects.equals(actor, movie.actor);
    }

Objects----new对象进行内容比较时使用

在这里插入图片描述

Objects.equals----避免空指针异常

Objects.equals(s1, s2)

在这里插入图片描述

StringBuilder----拼接数组里的字符

在这里插入图片描述

在这里插入图片描述

StringBuilder sb = new StringBuilder();

在这里插入图片描述
可以使用链式结构

变量.append().append().append().reverse();
//拼接数组里的字符
StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < arr.length; i++) {
            sb.append(i == arr.length-1 ? arr[i] : arr[i] + ", ");
        }
        sb.append("]");
        System.out.println(sb);
拿出StringBuilder里的字符
//遍历拿出所以字符
for (int i = 0; i < sb.length(); i++) {
            char ch = sb.charAt(i);
}

Math

在这里插入图片描述

在这里插入图片描述

System

在这里插入图片描述

在这里插入图片描述

BigDecimal----解决浮点型运算失真的问题

在这里插入图片描述

在这里插入图片描述

//获取BigDecima对象
double a = 12;
double b = 5;
BigDecimal a = BigDecimal.valueOf(a);//将数据a封装到BigDecimal中。
BigDecimal b = BigDecimal.valueOf(b);
double c = a.divide(b);
double c = BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b)).doubleValue();

在这里插入图片描述

日期与时间

Data----getTime

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

SimpleDataFormat----format 、 parse

在这里插入图片描述

format----将Data对象格式成时间格式

在这里插入图片描述

在这里插入图片描述

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a ");
		//EEE 代表 星期几 , a 代表 上下午 。

parse----将字符串时间格式解析成Data对象

在这里插入图片描述
字符串日期格式必须与SimpleDataFormat的格式相同。

Calendar

在这里插入图片描述

        Calendar cal = Calendar.getInstance();
		//直接调方法,不是new对象。

在这里插入图片描述

JDK8开始新增日期API----日期

在这里插入图片描述

LocalDate、LocalTime、LocalDateTime

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Instant

在这里插入图片描述

DateTimeFormatter

在这里插入图片描述

Duration/Period

在这里插入图片描述

在这里插入图片描述

ChronoUnit

在这里插入图片描述

包装类----toString、valueOf

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

toString----把基本类型数据转成字符串类型数据

在这里插入图片描述

//把数组内容转成集合,可以直接输出
Arrays.toString();

valueOf----把字符串类型数据转成基本类型数据

	//直接调用valueOf,不用记的麻烦。
	String s = Integer.valueOf();
	String s = Double.valueOf();

正则表达式

在这里插入图片描述

匹配规则----matches

在这里插入图片描述

matches("\\d") \\要求字符串内容为一个,且范围为0-9matches("\\d{4}") \\要求字符串内容要大于4个,且范围为0-9matches("\\d{4,20}") \\要求字符串内容要大于4,且小于20个,且范围为0-9matches("1[3-9]\\d{9}") \\要求字符串第一个字符为1,第二个字符范围为3-9,其余的字符个数为9且范围为0-9matches("\\.") \\要求字符为"."matches("1?") \\要求1出现一次或者不出现。 //以此类推*、+ 。

在这里插入图片描述

爬取信息

在这里插入图片描述

Arrays----数组排序

在这里插入图片描述

使用binarySearch时,必须让数组排好序,否则会出bug 。

Arrays.toString()  //打印数组内容

自定义类的排序----Comparator

在这里插入图片描述

自定义类排序:
Arrays.sort(Student, new Comparator<Student>() {
	//如果是自定义的学生类,想要按照年龄、身高来排序,方法如下:
            @Override
            public int compare(Student o1, Student o2) {    
                return o1.getAge() - o2.getAge();
                return Double.compare(o1.getHeight() , o2.getHeight());
                //小数的比较。因为return返回的是int类型。
            }
        });

常见算法

选择排序

在这里插入图片描述

for (int i = 0; i < arr.length - 1; i++) {
            for (int j = i+1 ; j < arr.length; j++) {
                if (arr[i] > arr[j]){
                    int temp = arr[i];
                    arr[i] = arr[j];
                    arr[j] = temp;
                }
            }
        }
        System.out.println(Arrays.toString(arr));

二分查找

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

 public static int search(int [] arr , int data){
        int left = 0;
        int right = arr.length-1;

        while (left <= right){
            int middle = (left + right)/2;
            if (data > arr[middle]){
                left = middle +1;
            }else if (data < arr[middle]){
                right = middle -1;
            }else {
                return middle;
            }
        }
        return -1;
    }

在这里插入图片描述

Lambda----简化 重写方法

在这里插入图片描述

在这里插入图片描述

Swimming s = new Swimming() {
            @Override
            public void swim() {
                System.out.println("");
            }
        };
Swimming s1 = () ->{
            System.out.println("");
        };


go(new Swimming() {
            @Override
            public void swim() {
                System.out.println("");
            }
        });
go(() ->{
            System.out.println("");
        });

在这里插入图片描述

在这里插入图片描述

集合

在这里插入图片描述
在这里插入图片描述

Collection集合体系

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Collection常用API

在这里插入图片描述

Collection的遍历方式

迭代器----Iterator

在这里插入图片描述

//遍历方式
Iterator<Integer> it = list.iterator();
        while (it.hasNext()){
            System.out.println(it.next());
        }

foreach/增强for循环----也可遍历数组

在这里插入图片描述

//快捷键
数组或集合名.for 回车

lambda表达式----forEach

在这里插入图片描述

//代码简化
list.forEach(new Consumer<String>() {
            @Override
            public void accept(String s) {
                System.out.println(s);
            }
        });

list.forEach( s ->{
                System.out.println(s);
            });

list.forEach( s -> System.out.println(s));

list.forEach(System.out::println);

Collection存储自定义类型的对象

//定义一个电影类
Collection<Movie> movies = new ArrayList<>();
        movies.add(new Movie("肖申克",9.9,"小李子"));
        movies.add(new Movie("成立",9.3,"陈列"));
        movies.add(new Movie("肖克",9.6,"李子"));
        
        //遍历----foreach
        for (Movie movie : movies) {
            System.out.println(movie.getName());
            System.out.println(movie.getScore());
            System.out.println(movie.getActor());
        }

Collection集合体系小结

在这里插入图片描述

常见数据结构

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

队列

在这里插入图片描述

数组

在这里插入图片描述

链表

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

二叉树

在这里插入图片描述

特点:
在这里插入图片描述

二叉查找树

在这里插入图片描述

在这里插入图片描述

平衡二叉树

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

红黑树

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

List

在这里插入图片描述

List<String> list = new ArrayList<>();

List特有API

在这里插入图片描述
在这里插入图片描述

List<String> list = new ArrayList();
list.indexOf(输入字符);//根据输入字符,提取字符所在的索引
list.substring(输入索引);//根据输入的索引,提取相对应的字符串

List的遍历方式

1.迭代器
2.foreach
3.lambda

4.for循环

for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

ArraysList集合底层原理

在这里插入图片描述

LinkedList集合底层原理

在这里插入图片描述

集合的并发修改异常问题----边遍历边删除

在这里插入图片描述

Iterator<String> it = list.iterator();
        while (it.hasNext()){
            String ele = it.next();
            if (ele.equals("要删除的对象")){
                it.remove(); //迭代器自己的方法
            }
        }
for (int i = 0; i < list.size(); i++) {
            String s = list.get(i);
            if (s.equals("1")){
                list.remove(i);
                i--;
            }
        }

for (int i = list.size()-1; i >=0 ; i--) {
            String s = list.get(i);
            if (s.equals("1")){
                list.remove(i);
            }
        }

泛型

概述

在这里插入图片描述
在这里插入图片描述

自定义泛型类

在这里插入图片描述
在这里插入图片描述

自定义泛型方法

在这里插入图片描述
在这里插入图片描述

自定义泛型接口

在这里插入图片描述
在这里插入图片描述

泛型通配符、上下限

在这里插入图片描述
在这里插入图片描述

Set

在这里插入图片描述

Set<String> set = new HashSet<>(); 

HashSet元素无序的底层原理:哈希表

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

HashSet元素去重复的底层原理

在这里插入图片描述

LinkedHashSet

在这里插入图片描述

TreeSet

在这里插入图片描述
在这里插入图片描述

自定义排序规则----Comparable

在这里插入图片描述
在这里插入图片描述

方式一:类自定义比较规则。
//接口Comparable
public class Student implements Comparable<Student> {
    private String name;
    private int age;
    private double height;

//重写排序规则
    @Override
    public int compareTo(Student o) {
        return this.age - o.age;//相同的元素会去掉
        return this.age - o.age >= 0 ? 1 :-1 ; //相同的元素可以保留。
    }
}
方式二:集合自带比较器对象进行规则自定。
Set<Student> set = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return o1.getAge() - o2.getAge();
                return Double.compare(o1.getHeight() , o2.getHeight());//浮点型比较

            }
        });

简化:
Set<Student> set = new TreeSet<>(( o1,  o2) ->
Double.compare(o1.getHeight() , o2.getHeight())  );

Set<Student> set = new TreeSet<>(( o1,  o2) -> o1.getAge() - o2.getAge()  );

可变参数----“int…nums”

在这里插入图片描述

 public static void sum(int...nums){
        
    }

集合Collections工具类

API----addAll、shuffle

在这里插入图片描述

Collections.addAll(list,"");

Collections.shuffle(list);

List集合自定义排序规则----Collections.sort

在这里插入图片描述

方式一:
Collections.sort(list);//在自定义类中要先重写比较规则,然后可以直接调用。

//使用接口Comparable
public class Student implements Comparable<Student> {
	//重写排序规则
    @Override
    public int compareTo(Student o) {
        return this.age - o.age;
        }
} 
方式二:
List<> list =new Arrayslist<>();

Collections.sort(list, new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getHeight(),o2.getHeight());//浮点型
                return o1.getAge() - o2.getAge();
            }
        });

简化:
Collections.sort(list,( o1,  o2) -> Double.compare(o1.getAge(),o2.getAge()) );

Map

概述

在这里插入图片描述

体系特点

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

Map<String,Integer> map = new HashMap<>();

常用API

在这里插入图片描述

遍历方式

键找值----keySet、get

在这里插入图片描述

Map<String,Integer> map = new HashMap<>();

//先拿到全部键
Set<String> keys = map.keySet();
//再遍历得每个键的值
        for (String key : keys) {
            int value = map.get(key);//获取值
            System.out.println(key +"===>" + value);
        }

键值对----entrySet、getKey、getValue

在这里插入图片描述

Map<String,Integer> map = new HashMap<>();

Set<Map.Entry<String, Integer>> entries = map.entrySet();
        for (Map.Entry<String, Integer> entry : entries) {
            String key =entry.getKey();
            int value = entry.getValue();
            System.out.println(keys +"===>" + value);
        }

lambda表达式----forEach

在这里插入图片描述

map.forEach(new BiConsumer<String, Integer>() {
            @Override
            public void accept(String s, Integer integer) {
                System.out.println(s + "---->" + integer);
            }
        });

简化:
map.forEach(( s,  integer) -> {
                System.out.println(s + "---->" + integer);
            });

案例

//随机输出定义的4个数据0
String[] s = {"A","B","C","D"};
        StringBuilder stringBuilder = new StringBuilder();
        Random r = new Random();
        for (int i = 0; i < 80; i++) {
            stringBuilder.append(s[r.nextInt(4)]);
        }
        System.out.println(stringBuilder);

        Map<Character,Integer> map = new HashMap<>();
        //
        for (int i = 0; i < stringBuilder.length(); i++) {
            char ch = stringBuilder.charAt(i);

            if (map.containsKey(ch)) {
                map.put(ch,map.get(ch) + 1);
            }else {
                map.put(ch,1);
            }
        }
        System.out.println(map);

Map集合的实现类----与Set集合差不多

在这里插入图片描述

HashMap

在这里插入图片描述

LinkedHashMap

在这里插入图片描述

TreeMap----自定义排序规则

在这里插入图片描述

方式一:类自定义比较规则。
//接口Comparable
public class Student implements Comparable<Student> {
    private String name;
    private int age;
    private double height;

//重写排序规则
    @Override
    public int compareTo(Student o) {
        return this.age - o.age;//相同的元素会覆盖
    }
}

//main方法中直接输出
Map<Student , Integer> map = new TreeMap<>();
System.out.println(map);
方式二:集合自带比较器
Map<Student , Integer> map = new TreeMap<>(new Comparator<Student>() {
            @Override
            public int compare(Student o1, Student o2) {
                return Double.compare(o1.getHeight(),o2.getHeight());//浮点型
            }
        });

嵌套集合

//嵌套集合格式:
Map<String, List<String>> map = new HashMap<>();
        List<String> list = new ArrayList<>();
        Collections.addAll(list,"A","B");
        map.put("小米",list);
        System.out.println(map);
        Map<String, List<String>> map = new HashMap<>();

        //创建集合,将list集合中的元素添加到Map集合中
        List<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"A","C");//直接添加多个数据
        map.put("小米",list1);

        List<String> list2 = new ArrayList<>();
        Collections.addAll(list2,"A","D");
        map.put("小蓝",list2);

        List<String> list3 = new ArrayList<>();
        Collections.addAll(list3,"A","B","C");
        map.put("小新",list3);

        System.out.println(map);

        //统计数据,算出map中值重复了多少

        Map<String,Integer> infos = new HashMap<>();//创建集合储存map中的值

        Collection<List<String>> values = map.values();//拿到map中的所有值,将它储存在Collection集合中。
        System.out.println(values); //values = [[A, D], [A, B, C], [A, C]]

        //遍历集合,把集合中的元素遍历出来
        for (List<String> value : values) {//这个是遍历Collection集合中所有的list集合
            for (String s : value) {//这是遍历list集合里的每个元素

                //判断infos集合中是否有这个元素
                if (infos.containsKey(s)){
                    infos.put(s,infos.get(s) + 1);
                }else {
                    infos.put(s,1);
                }
            }
        }

        System.out.println(infos);

创建不可变集合----少用

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

JDK8不可用
List<Double> list = List.of(12.1,34.5,67.8);

Stream流

概述

在这里插入图片描述

		//名字分类,传统办法:
		List<String> name = new ArrayList<>();
        Collections.addAll(name,"张倩", "张强前","张作者","周中");//添加多个元素
		//按姓氏分
        List<String> zhangName = new ArrayList<>();
        for (String s : name) {
            if (s.startsWith("张")){
                zhangName.add(s);
            }
        }
        System.out.println(zhangName);
		//按姓名长度分
        List<String> zhangThereName = new ArrayList<>();
        for (String s : zhangName) {
            if (s.length()==3){
                zhangThereName.add(s);
            }
        }
        System.out.println(zhangThereName);
        
		//stream流一步完成//可以支持链式结构
        name.stream().filter(s-> s.startsWith("张")).
        filter(s-> s.length()==3).forEach(s -> System.out.println(s));
    

在这里插入图片描述

集合、数组获取Stream流

在这里插入图片描述

在这里插入图片描述

        //Collection集合获取流
        List<String> list = new ArrayList<>();
        Stream<String> s = list.stream();

        //Map集合获取流
        Map<String,Integer> map = new HashMap<>();
        Stream<String> keyStream = map.keySet().stream();//键获取流
        Stream<Integer> valueStream = map.values().stream();//值获取流
        Stream<Map.Entry<String,Integer>> keyAndKeyStream = map.entrySet().stream();//键值对获取流

        //数组获取流
        String[] names = {"小米","小红","小新"};
        Stream<String> nameStream = Arrays.stream(names);
        Stream<String> nameStream1 = Stream.of(names);

Stream常用API

在这里插入图片描述

在这里插入图片描述

        name.stream().filter(new Predicate<String>() {
            @Override
            public boolean test(String s) {
                return s.startsWith("张");
            }
        });

简化:
        name.stream().filter(s-> s.startsWith("张")).
//遍历
).forEach(s -> System.out.println(s));

简化:
).forEach(System.out::println);
//返回流长度
long size = list.stream().count();
//map加工方法
//给集合元素前加上字符串
list.stream().map(s -> "" + s).

//把集合所有的元素都加工成Student对象
list.stream().map(s -> new Student(s)).forEach(s -> System.out.println(s));

简化:
list.stream().map(Student::new).forEach(System.out::println);  
//合并两个流
Stream<String> = Stream.concat(stream1,stream2);

综合应用

one.stream().max((e1,e2) -> Double.compare(e1.getSalary()+e1.getBonus() ,e2.getSalary()+e2.getBonus())).
                map(e -> new Top(e.getName(),e.getSalary()+e.getBonus())).get();
//max方法自定义类比较方法,直接取出最大值对象,map方法将对象储存到新的类对象中。
one.stream().sorted((e1,e2) -> Double.compare(e1.getSalary()+e1.getBonus() ,e2.getSalary()+e2.getBonus()))
                .skip(1).limit(one.size()-2).forEach(s -> {
                    allMoney += s.getBonus() + s.getSalary();//要在main方法外定义一个公开静态成员变量
                });
//sorted方法自定义类比较规则, 将集合中的对象排序,

收集Stream流

在这里插入图片描述

在这里插入图片描述

		//List集合
		Stream<String> s1 = name.stream().filter(s -> s.startsWith("张"));
        List<String> list = s1.collect(Collectors.toList());
        System.out.println(list);
        
        //stream流只能使用一次,再次使用时要重写stream() 。
        //Set集合
		Stream<String> s2 = name.stream().filter(s -> s.startsWith("张"));
		Set<String> set = s2.collect(Collectors.toSet());
        System.out.println(set);
        
        //数组
        Stream<String> s3 = name.stream().filter(s -> s.startsWith("张"));
		Object[] arr =s3.toArray();
        System.out.println(Arrays.toString(arr));

异常

概述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

常见运行时异常

在这里插入图片描述

常见编译时异常

在这里插入图片描述

异常的默认处理流程

在这里插入图片描述

编译时异常的处理机制

在这里插入图片描述

在这里插入图片描述

try…catch…——出现异常可以使程序正常运行

在这里插入图片描述
快捷键:Ctrl + Alt + T ----try/catch

在这里插入图片描述

在这里插入图片描述

运行时异常的处理机制

在这里插入图片描述

异常处理使代码更稳健

		//使异常出现后代码可以继续运行,而不会程序死亡。
		Scanner sc = new Scanner(System.in);
        while (true){
            try {//可能出现异常的代码行
                System.out.println("请输入定价:");
                String priceStr = sc.nextLine(); //只能输入一行代码。
                double price = Double.valueOf(priceStr);//转换成double类型
                if (price > 0){
                    System.out.println("定价:"+price);
                    break;
                }else {
                    System.out.println("输入有误");
                }
            } catch (Exception e) {//处理异常,使出现异常后代码可以继续运行
                System.out.println("重写输入");
            }
        }

自定义异常

在这里插入图片描述

在这里插入图片描述

编译时异常
//定义一个异常类继承Exception
public class Text extends Exception{
	//重写构造器
    public Text(String message) {
        super(message);
    }
    public Text() {
    }
}



	public static void main(String[] args) {

        try {
            checkAge(-34);
        } catch (Text e) {
            throw new RuntimeException(e);
        }
    }

    public static void checkAge(int age) throws Text {
        if (age < 0 || age >200){
            //抛出一个异常对象给调用者
            //throw:在方法内部直接创建一个异常对象,并从此点抛出
            //throws:用在方法申明上的,抛出方法内部的异常。
            throw new Text(age + " is false");
        }else {
            System.out.println("合法");
        }
    }
运行时异常
//定义一个类继承RuntimeException
public class Text extends RuntimeException{
    public Text(String message) {
        super(message);
    }

    public Text() {
    }
}



	public static void main(String[] args) {

        try {
            checkAge(-34);
        } catch (Text e) {
            throw new RuntimeException(e);
        }
    }

    public static void checkAge(int age) throws Text {
        if (age < 0 || age >200){
            //抛出一个异常对象给调用者
            //throw:在方法内部直接创建一个异常对象,并从此点抛出
            //throws:用在方法申明上的,抛出方法内部的异常。
            throw new Text(age + " is false");
        }else {
            System.out.println("合法");
        }
    }

日志框架

概述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

技术体系

在这里插入图片描述

Logback

概述

在这里插入图片描述

在这里插入图片描述

快速入门

在这里插入图片描述

public static final Logger LOGGER = LoggerFactory.getLogger("MovieSystem.class");
//logback.xml 文件代码
//<file>和<fileNamePattern>文件要自己改变路径
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <!--
        CONSOLE :表示当前的日志信息是可以输出到控制台的。
    -->
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <!--输出流对象 默认 System.out 改为 System.err-->
        <target>System.out</target>
        <encoder>
            <!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
                %msg:日志消息,%n是换行符-->
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]  %c [%thread] : %msg%n</pattern>
        </encoder>
    </appender>
 
    <!-- File是输出的方向通向文件的 -->
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
            <charset>utf-8</charset>
        </encoder>
        <!--日志输出路径-->
        <file>D:\Logback\data.log</file>
        <!--指定日志文件拆分和压缩规则-->
        <rollingPolicy
                class="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy">
            <!--通过指定压缩文件名称,来确定分割文件方式-->
            <fileNamePattern>D:\Logback\data-%d{yyyy-MM-dd}.log%i.gz</fileNamePattern>
            <!--文件拆分大小-->
            <maxFileSize>1MB</maxFileSize>
        </rollingPolicy>
    </appender>
 
    <!--
    level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR    |    ALL 和 OFF
   , 默认debug
    <root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。
    -->
    <root level="ALL">
        <!-- 注意:如果这里不配置关联打印位置,该位置将不会记录日志-->
        <appender-ref ref = "CONSOLE"/>
        <appender-ref ref="FILE" />
    </root>
</configuration>

	//记录系统的日志信息,会在路径生成TXT文档
	public static final Logger LOGGER =  LoggerFactory.getLogger("Text");
    public static void main(String[] args) {
        try {
            LOGGER.debug("开始运行");
            LOGGER.info("开始记录日志");
            int a = 10;
            int b = 0;
            LOGGER.trace("a:" + a);
            LOGGER.trace("b:" + b);
            System.out.println(a/b);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("功能出现异常" + e);
        }
    }

配置详情

输出位置、格式设置

在这里插入图片描述

<appender-ref ref = "CONSOLE"/> //会打印在控制台中,不打就不会影响运行流程。
<appender-ref ref="FILE" /> //会打印在生产文件中
		<!--输出流对象 默认 System.out 改为 System.err-->//改完后打印内容会变红
        <target>System.out</target>
//符号代表的意思
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度
                %msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]  %c [%thread] : %msg%n</pattern>
日志级别设置

在这里插入图片描述

在这里插入图片描述

<root level="ALL">

File

在这里插入图片描述

在这里插入图片描述

概述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

//绝对路径
//路径的三种写法
File file = new File("D:\\Logback\\data.log");
File file = new File("D:/Logback/data.log");
File file = new File("D:" +File.separator+ "Logback"+ File.separator+"data.log");


//相对路径
//创建一个New Project,而不是Empty Module。
//从src目录开始查找就行
File f = new File("src/data.txt");

常用API

判断文件类型、获取文件信息

在这里插入图片描述

创建、删除文件

在这里插入图片描述

遍历

在这里插入图片描述

方法递归

概述

在这里插入图片描述

算法流程

在这里插入图片描述

	public static void main(String[] args) {
        System.out.println(f(5));
        //f(4)*5
        //f(3)*4*5
        //f(2)*3*4*5
        //f(1)*2*3*4*5
    }


    //阶乘计算
    public static int f(int n){
        if (n == 1){
            return 1;
        }else {
            return f(n-1)*n;
        }
    }
	public static void main(String[] args) {
        System.out.println(f(100));
    }


	//求和计算
    public static int f(int n){
        if (n == 1){
            return 1;
        }else {
            return f(n-1)+n;
        }
    }

案例

在这里插入图片描述

	//公式:f(x) - f(x)/2 - 1 = f(x-1)
	//      f(x) = 2*f(x) + 2  
	public static void main(String[] args) {
        System.out.println(f(1));
    }

    public static int f (int n){
        if (n == 10){
            return 1;
        }else {
            return 2*f(n+1) + 2;
        }
    }

非规律化递归

文件搜索

在这里插入图片描述

	public static void main(String[] args) {
        search(new File("D:/"),"#ib_redo6");
    }

	//文件搜索方法
    public static void search (File dir , String fileName){
        //判断源dir是否是目录
        if (dir != null && dir.isDirectory()){
            //提取一级文件
            File [] files = dir.listFiles();
            //判断一级文件对象集合是否存在
            if (files != null && files.length > 0 ){
                //遍历所有一级文件对象
                for (File file : files) {
                    //判断一级文件对象是文件还是目录
                    if (file.isFile()){
                        //为文件的话,判断是否为要查找的文件
                        if (file.getName().contains(fileName)){
                            System.out.println("找到了" + file.getAbsolutePath());
                        }
                    }else {
                        //为目录,流程重复
                        search(file , fileName);
                    }
                }
            }
        }else {
            System.out.println("目录不存在");
        }
    }

啤酒问题

在这里插入图片描述

	public static void main(String[] args) {
        buy(10);
    }


    //定义一个变量来储存总共买酒的数量
    public static int totalNumber;

    //定一个义变量储存每次用酒瓶换完酒后酒瓶剩余的数量
    public static int lastBottleNumber;

    //定一个义变量储存每次用瓶盖换完酒后瓶盖剩余的数量
    public static int lastCoverNumber;


    //买酒方法
    public static void buy(int money){
        //直接计算钱可以买多少酒
        int buyNumber = money / 2;
        totalNumber += buyNumber;

        //统计本轮瓶子数和盖子数,要加上上次换酒后剩的。
        int BottleNumber =lastBottleNumber + buyNumber;
        int CoverNumber = lastCoverNumber + buyNumber;

        //拿酒瓶换钱
        int allMoney = 0;
        if (BottleNumber >= 2){
            allMoney += (BottleNumber/2) * 2;
        }
        lastBottleNumber = BottleNumber%2;

        //拿瓶盖换钱
        if (CoverNumber >= 4){
            allMoney += (CoverNumber/4) * 2;
        }
        lastCoverNumber = CoverNumber%4;

		//判断是否可以继续买酒
        if (allMoney >= 2){
            buy(allMoney);
        }else {
            System.out.println("酒的总数" + totalNumber);
            System.out.println("剩余瓶子数" + lastBottleNumber);
            System.out.println("剩余盖子数" + lastCoverNumber);
        }
    }

字符级

概述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

解码、编码操作

在这里插入图片描述

		String name = "abc我爱你";
		byte [] bytes = name.getBytes();//将字符串默认编码成字节
		System.out.println(bytes.length);
        System.out.println(Arrays.toString(bytes));//输出字节编码
		String rs = new String(bytes);//默认解码
		System.out.println(rs);


		String name = "abc我爱你";
        byte [] bytes = name.getBytes("GBK");//指定编码
        System.out.println(bytes.length);
        System.out.println(Arrays.toString(bytes));
        String rs = new String(bytes,"GBK");//指定解码
        System.out.println(rs);

IO流

概述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

字节流的使用

在这里插入图片描述

文件字节输入流:每次读取一个字节

在这里插入图片描述

		//创建字节输入流管道与源文件路径接通
		InputStream is = new FileInputStream(new File("src/data"));
        InputStream is = new FileInputStream("src/data");//简化写法
        //读取一个字符
        int b1 = is.read();
        System.out.println((char) b1);
        int b2 = is.read();
        System.out.println((char) b2);
        int b3 = is.read();
        System.out.println((char) b3);

		//循环读取所有字符
		//但是不能读取中文,因为read每次只能读取一个字节,而中文包含三个字节,会出现bug
		int b;
        while ((b = is.read()) != -1){
            System.out.print((char) b);
        }

文件字节输入流:每次读取一个字节数组

在这里插入图片描述

        InputStream is = new FileInputStream("src/data");

        //定义一个字节数组,用来储存读取的字节
 		byte[] buffer = new byte[3];
        int len = is.read(buffer);//读取字节到数组中,返回字节个数
        System.out.println(len);//输出读取字节个数
        
        
        //编译字节数组
        //但是当字节数组个数不满足3个时,会出现bug
        String rs = new String(buffer);//解码
        System.out.println(rs);

		//读取多少字节就从数组中输出多少个字节,不会出bug
		String rs = new String(buffer,0,len);//解码,把字节转成字符串
		System.out.println(rs);
        InputStream is = new FileInputStream("src/data");
		//循环读取所有字符
		byte [] buffer = new byte[3];
        int len;//记录每次读取的字节数
        while ((len = is.read(buffer)) != -1){
            System.out.print(new String(buffer, 0, len));//解码
        }
        //但是此种方式还是会出现bug,当字符形式为“ab我”时,为了读取3个字符,会把中文的三个字符拆出来读取一个。
        

文件字节输入流:一次读完全部字节

在这里插入图片描述

在这里插入图片描述

        //创建一个文件储存所有字节
        File f = new File("src/data");
        InputStream is = new FileInputStream(f);

        //定义一个字节数组,大小和文件一样
        byte [] buffer = new byte[(int) f.length()];
        int len = is.read(buffer);//读取字节到数组中//编码
        System.out.println(len);
        System.out.println(f.length());
        System.out.println(new String(buffer));//解码


		//读取全部字节的API
		//但是这个API是从JDK9才开始支持
		byte [] buffer = is.readAllBytes();
		System.out.println(new String(buffer));

文件字节输出流:写字节数据到文件

在这里插入图片描述

在这里插入图片描述

		//创建一个文件字节输出流管道与目标文件接通
        OutputStream os = new FileOutputStream("src/date.txt");//每次输出前,会先清空文件之前的数据
        OutputStream os = new FileOutputStream("src/date.txt",true);//每次输出可以叠加之前的数据
        
        //写一个字节出去
        os.write('a');
        os.write(97);
        os.write('徐');//无法输出,因为每次只能输出一个字节
        os.write("\r\n".getBytes());//换行

        //写一个数组出去
        byte [] buffer = {98,'a','b'};
        os.write(buffer);
        os.write("\r\n".getBytes());//换行

        //将一个字符串转成字节储存到数组
        byte [] buffers = "abc我是中国人".getBytes();
        os.write(buffers);//输出数组
        os.write("\r\n".getBytes());

        //输出数组的一部分
        byte [] buffer1 = {'a',97,98};
        os.write(buffer1,0,1);//就会输出“a、97”

		//写完数据,一定要刷新或释放数据
        //写完数据,必须刷新数据,把缓存的数据到输出。//使用后可以继续使用流
		os.flush();
        //释放资源,包含刷新数据。//使用后不可以继续使用流
        os.close();

文件拷贝

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

 		//拷贝视频、文件、图片
        try {
            //输入流
            InputStream is = new FileInputStream("");
            //输出流
            OutputStream os = new FileOutputStream("");

            //数组储存字节
            byte[] buffer = new byte[1024];
            int len;//每次读取长度
            //循环输出字节数组
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            System.out.println("完成");
            
            //关闭流
            os.close();
            is.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

资源释放的方式

try-catch-finally

在这里插入图片描述

		//定义在try外,finall才能执行
		InputStream is = null;
        OutputStream os = null;

        //拷贝视频、文件、图片
        try {
            //输入流
            is = new FileInputStream("");
            //输出流
            os = new FileOutputStream("");
            //数组储存字节
            byte[] buffer = new byte[1024];
            int len;//每次读取长度
            //循环输出字节数组
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            System.out.println("完成");
        } catch (Exception e) {
            e.printStackTrace();

            //无论代码是正常还是出现异常都会执行这里
        } finally {
            //关闭流
            try {
                //非空判断
                if (os != null)os.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
            try {
                //非空判断
                if (os != null)is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

try-with-resource

在这里插入图片描述

		try (
                //这里面只能放置资源对象,用完会自动关闭
                //自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)
                
                //输入流
                InputStream is = new FileInputStream("");
                //输出流
                OutputStream os = new FileOutputStream("");

                ){

            //数组储存字节
            byte[] buffer = new byte[1024];
            int len;//每次读取长度
            //循环输出字节数组
            while ((len = is.read(buffer)) != -1) {
                os.write(buffer, 0, len);
            }
            System.out.println("完成");

        } catch (Exception e) {
            e.printStackTrace();

        }

在这里插入图片描述

在这里插入图片描述

字符流的使用

在这里插入图片描述
在这里插入图片描述

文件字符输入流:一次读取一个字符

在这里插入图片描述

		//创建一个字符输入流管道与源文件相接
        Reader fr = new FileReader("src/data.txt");

        //读取一个字符
        int code = fr.read();
        System.out.println((char) code);

        //循环读取所有字符
        int code;
        while ((code = fr.read()) != -1){
            System.out.print((char) code);
        }

文件字符输入流:一次读取一个字符数组

在这里插入图片描述

		//创建一个字符输入流管道与源文件相接
        Reader fr = new FileReader("src/data.txt");

		//用循环读取一个字符数组数据
		char [] buffer = new char[1024];
        int len;
        while ((len = fr.read(buffer)) != -1){
            String rs = new String(buffer,0,len);
            System.out.println(rs);
        }

文件字符输出流

在这里插入图片描述

		//创建一个字符输出流管道与目标文件接通
        Writer fw = new FileWriter("src/data");//覆盖管道,会清空之前文件的数据
        Writer fw = new FileWriter("src/data",true);//追加数据,不会清空之前文件的数据

        //写一个字符出去
        fw.write('a');
        fw.write(97);
        fw.write('徐');//不会出bug
        fw.write("\r\n");//换行

        //写一个字符串出去
        fw.write("abc我是中国人");
        fw.write("\r\n");//换行

        //写一个字符数组出去
        char [] chars = "abc我是中国人".toCharArray();//把字符串转成字符
        fw.write(chars);
        fw.write("\r\n");//换行

        //写字符串的一部分出去
        fw.write("abc我是中国人",0,3);
        fw.write("\r\n");//换行

        //写字符数组的一部分出去
        fw.write(chars,3,5);
        fw.write("\r\n");//换行

		fw.flush();//刷新流
        fw.close();//关闭流

在这里插入图片描述

缓冲流

概述

在这里插入图片描述

在这里插入图片描述

字节缓冲流

在这里插入图片描述

在这里插入图片描述

		//拷贝视频、文件、图片
        try (
                //这里面只能放置资源对象,用完会自动关闭
                //自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)
                
                //输入流
                InputStream is = new FileInputStream("");
                //把原始的字节输入流包装成高级的缓冲字节输入流
                InputStream bis = new BufferedInputStream(is);

                //输出流
                OutputStream os = new FileOutputStream("");
                //把原始的字节输出流包装成高级的缓冲字节输出流
                OutputStream bos = new BufferedOutputStream(os);

                ){

            //数组储存字节
            byte[] buffer = new byte[1024];
            int len;//每次读取长度
            //循环输出字节数组
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            System.out.println("完成");

        } catch (Exception e) {
            e.printStackTrace();
        }

字节缓冲流的性能分析

原始流加上8kb的桶,效果和高级流一样

		//高级流拷贝
		//拷贝视频、文件、图片
        try (
                //这里面只能放置资源对象,用完会自动关闭
                //自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)
                
                //输入流
                InputStream is = new FileInputStream("");
                //把原始的字节输入流包装成高级的缓冲字节输入流
                InputStream bis = new BufferedInputStream(is);

                //输出流
                OutputStream os = new FileOutputStream("");
                //把原始的字节输出流包装成高级的缓冲字节输出流
                OutputStream bos = new BufferedOutputStream(os);

                ){

            //数组储存字节
            byte[] buffer = new byte[1024];
            int len;//每次读取长度
            //循环输出字节数组
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            System.out.println("完成");

        } catch (Exception e) {
            e.printStackTrace();
        }


//原始流加上8kb的桶,效果和高级流一样


		//原始流拷贝
		//拷贝视频、文件、图片
        try (
                //这里面只能放置资源对象,用完会自动关闭
                //自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)
                
                //输入流
                InputStream is = new FileInputStream("");
                //输出流
                OutputStream os = new FileOutputStream("");
                
                ){

            //数组储存字节
            byte[] buffer = new byte[1024 * 8];
            int len;//每次读取长度
            //循环输出字节数组
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            System.out.println("完成");

        } catch (Exception e) {
            e.printStackTrace();
        }

字符缓冲流

输入流

在这里插入图片描述

		try (
                //这里面只能放置资源对象,用完会自动关闭
                //自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)
                //输入流
                Reader fr = new FileReader("src/data");
                //把原始的字符输入流包装成高级的缓冲字符输入流
                BufferedReader br = new BufferedReader(fr);

        ){

            //数组储存字符
            char[] buffer = new char[1024];
            int len;//每次读取长度
            //循环输出字符数组
            while ((len =br.read(buffer)) != -1) {
                String rs = new String(buffer,0,len);
                System.out.print(rs);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
		//经典代码
		try (
                //这里面只能放置资源对象,用完会自动关闭
                //自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)
                //输入流
                Reader fr = new FileReader("src/data");
                //把原始的字符输入流包装成高级的缓冲字符输入流
                BufferedReader br = new BufferedReader(fr);

        ){
            String line;
            while ((line = br.readLine()) != null){
                System.out.println(line);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

输出流

在这里插入图片描述

		//创建一个字符输出流管道与目标文件接通
        Writer fw = new FileWriter("src/data");//覆盖管道,会清空之前文件的数据
        Writer fw = new FileWriter("src/data01",true);//追加数据,不会清空之前文件的数据
        //把低级字符输出流包装成缓冲字符输出流
        BufferedWriter bw = new BufferedWriter(fw);

        //写一个字符出去
        bw.write('a');
        bw.write(97);
        bw.write('徐');//不会出bug
        bw.newLine();//bw.write("\r\n");//换行

        //写一个字符串出去
        bw.write("abc我是中国人");
        bw.write("\r\n");//换行

        //写一个字符数组出去
        char [] chars = "abc我是中国人".toCharArray();
        bw.write(chars);
        bw.newLine();//bw.write("\r\n");//换行

        //写字符串的一部分出去
        bw.write("abc我是中国人",0,3);
        bw.newLine();//bw.write("\r\n");//换行

        //写字符数组的一部分出去
        bw.write(chars,3,5);
        bw.newLine();//bw.write("\r\n");//换行

        fw.flush();//刷新流
        bw.close();//关闭流

案例

在这里插入图片描述

		try (
                //创建字符缓冲输入流
                BufferedReader br = new BufferedReader(new FileReader("src/data.txt"));
                //创建一个字符缓冲输出流
                BufferedWriter bw = new BufferedWriter(new FileWriter("src/date"));

                ){

            //创建一个集合储存读取文件所有数据
            List<String> data = new ArrayList<>();

            //循环读取数据
            String line;
            while ((line = br.readLine()) != null){
                data.add(line);
            }
            System.out.println(data);

            //自定义排序规则
            List<String> sizes = new ArrayList<>();
            Collections.addAll(sizes,"一","二","三","四","五","六","七");

            Collections.sort(data, new Comparator<String>() {
                @Override
                public int compare(String o1, String o2) {
                //indexOf是根据字符所在的位置返回集合的索引//根据字符提取索引
                //substring是根据开始索引和最终索引提取这一段的字符//根据索引提前字符
                    return sizes.indexOf(o1.substring(0,o1.indexOf("、"))) -
                            sizes.indexOf(o2.substring(0,o2.indexOf("、")));
                }
            });
            
            System.out.println(data);

            //循环遍历集合
            for (String datum : data) {
                bw.write(datum);
                bw.newLine();//换行
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

转换流

在这里插入图片描述
在这里插入图片描述

字符输入转换流

在这里插入图片描述

		//字节输入流
        InputStream is = new FileInputStream("src/");
        //字节输入流转换成字符输入流
        Reader isr = new InputStreamReader(is);//默认以UTF-8的方式转成字符
        Reader isr = new InputStreamReader(is, "GBK");//以指定GBK编码方式转成字符


        //把字符输入流包装成缓冲字符输入流
        BufferedReader br = new BufferedReader(isr);
        String line;
        while ((line = br.readLine()) != null){
            System.out.println(line);
        }

字符输出转换流

在这里插入图片描述

在这里插入图片描述

        //字节输出流
        OutputStream os = new FileOutputStream("src");
        //把字节输出流转成字符输出流
        Writer bos = new OutputStreamWriter(os);//以默认UTF-8发生输出字符
        Writer bos = new OutputStreamWriter(os,"GBK");//以指定GBK方式输出字符

        //把字符输出流包装成缓冲字符输出流
        BufferedWriter bw = new BufferedWriter(bos);

        bw.write();
        bw.close();

序列化对象

在这里插入图片描述

对象序列化

在这里插入图片描述

在这里插入图片描述

		//创建学生对象
        Student s = new Student("阿康","ak","123",20);
        //对象序列化:使用对象字节输出流包装字节输出流
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/dd"));

        //调用序列化方法
        oos.writeObject(s);
		//释放资源
        oos.close();

//对象要实现序列化,必须实现Serializable接口
public class Student implements Serializable {
}

对象反序列化

在这里插入图片描述

在这里插入图片描述

		//创建对象字节输入流管道包装字节输入流
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/dd"));

        //调用对象字节反序列化方法
        Student s = (Student) ois.readObject();

        System.out.println(s);

对象序列化规则:
//对象要实现序列化,必须实现Serializable接口
//申明序列化的版本号
//序列化的版本号和反序列化的版本号必须一致才不会出错
//transient修饰的成员变量不参与序列化

//对象要实现序列化,必须实现Serializable接口
public class Student implements Serializable {
    
    //申明序列化的版本号
    //序列化的版本号和反序列化的版本号必须一致才不会出错
    private static final long serialVersionUID = 1;
    
    private String name;
    private String loginName;

    //transient修饰的成员变量不参与序列化
    private transient String passWord;
    private int age;

    public Student() {
    }
}

打印流

PrintStream、PrintWriter

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

		//两种写法
        PrintStream ps = new PrintStream("src/ps.txt");
        PrintStream ps = new PrintStream(new FileOutputStream("src/ps.txt"));
        //要追加数据只能使用低级管道
        PrintStream ps = new PrintStream(new FileOutputStream("src/ps.txt",true));

输出语句的重定向

在这里插入图片描述

		//改变输出语句的位置
        PrintStream ps = new PrintStream("src/ps");
        System.setOut(ps);//把系统打印流改成我们自己的打印流

        System.out.println("锦瑟无端五十闲");
        System.out.println("一线一柱思华年");

Properties

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

		//使用Properties把键值对信息存到文件中去
        Properties pp = new Properties();
        //信息输入
        pp.setProperty("heima","123");
        System.out.println(pp);

        pp.store(new FileWriter("src/pp"),"i am happy");
		//Properties读取属性文件中的键值对信息
        Properties properties = new Properties();
        System.out.println(properties);

        //加载属性文件中键值对数据到属性对象Properties中去
        properties.load(new FileReader("src/pp"));
        System.out.println(properties);

        //通过键拿到对应的值
        String rs = properties.getProperty("heima");
        System.out.println(rs);

IO流框架

在这里插入图片描述

		//文件复制
        IOUtils.copy(new FileInputStream("") , new FileOutputStream(""));

        //完成文件复制到某个文件夹下
        FileUtils.copyFileToDirectory(new File(""),new File(""));

        //完成文件夹复制到某个文件夹下
        FileUtils.copyDirectoryToDirectory(new File(""),new File(""));

        //完成删除文件夹
        FileUtils.deleteDirectory(new File(""));

        //java自己也有一些一行代码完成复制的操作
        Files.copy(Paths.get(""),Paths.get(""));

线程

概述

在这里插入图片描述
在这里插入图片描述

多线程的创建

方式一:继承Thread类

在这里插入图片描述

在这里插入图片描述

//1、定义一个线程类继承Thread
class MyThread extends Thread {
    //2、重写run方,里面是定义线程以后干什么
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程启动" + i);
        }
    }
}

	public static void main(String[] args) {
        //3、new一个线程对象
        Thread t = new MyThread();//多态
        //4、调用start方法启动线程,其实是调用run方法
        t.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("主线程启动" + i);
        }
    }

在这里插入图片描述

方式二:实现Runnable接口

在这里插入图片描述

//1、定义一个线程任务类 实现Runnable接口
class MyRunnable implements Runnable {
    //2、重写run方法,定义线程的执行任务
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println("子线程输出" + i);
        }
    }
}


	public static void main(String[] args) {
        //3、创建一个任务对象
        Runnable target = new MyRunnable();//多态
        //4、把任务对象交给Thread处理
        Thread t = new Thread(target);

        //5、启动线程
        t.start();

        for (int i = 0; i < 5; i++) {
            System.out.println("主线程输出" + i);
        }
    }

在这里插入图片描述

在这里插入图片描述

	public static void main(String[] args) {
        //内部类写法
        Runnable target = new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程1输出" + i);
                }
            }
        };
        Thread t = new Thread(target);
        t.start();

        //简化写法
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程2输出" + i);
                }
            }
        }).start();


        //再简化
        new Thread(() -> {
                for (int i = 0; i < 5; i++) {
                    System.out.println("子线程3输出" + i);
                }
        }).start();


        for (int i = 0; i < 5; i++) {
            System.out.println("主线程输出" + i);
        }
    }

方式三:实现Callable接口----可返回线程的执行结果

在这里插入图片描述

在这里插入图片描述

//1、定义一个任务类 实现Callable接口
class MyCallable implements Callable<String> {
	//创建一个有参构造器
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }

    //重写call方法(任务方法)
    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 0; i <=n ; i++) {
            sum += i;
        }
        return "子线程输出结果" + sum;
    }
}


	public static void main(String[] args) {
        //3、创建Callable任务对象
        Callable<String> call = new MyCallable(100);//没法直接交给Thread
        //4、把Callable任务对象 交给 FutureTask 对象
        //FutureTask对象的作用1:使Runnable的对象(实现Runnable接口),可以交给Thread
        //FutureTask对象的作用2:可以在线程执行完毕之后调用其get方法得到线程执行的结果
        FutureTask<String> f = new FutureTask<>(call);
        //5、交给线程处理
        Thread t = new Thread(f);
        t.start();//启动

        try {
            //如果f任务没有执行完毕,这里的代码会等到线程执行完毕才启动
            //获取线程执行结果
            String rs = f.get();
            System.out.println("结果为" + rs);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

在这里插入图片描述

Thread的常用方法

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

	public static void main(String[] args) {
        Thread t1 = new MyThread();
        t1.setName("1号");
        t1.start();
        System.out.println(t1.getName());

        Thread t2 = new MyThread();
        t2.setName("2号");
        t2.start();
        System.out.println(t2.getName());

        Thread m = Thread.currentThread();
        System.out.println(m.getName());

        for (int i = 0; i < 5; i++) {
            System.out.println("main线程输出" + i);
        }
    }

在这里插入图片描述

		//3、创建一个任务对象
        Runnable target = new MyRunnable();
        //4、把任务对象交给Thread处理
        Thread t = new Thread(target);
        Thread t = new Thread(target,"1号");
//创建一个线程类
public class MyThread extends Thread{
    public MyThread() {
    }
    //创建一个有参构造器
    public MyThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "输出" + i);
        }
    }
}

Thread t1 = new MyThread("1号");
//        t1.setName("1号");
        t1.start();
        System.out.println(t1.getName());

在这里插入图片描述

	public static void main(String[] args) throws Exception {
        for (int i = 1; i <= 5; i++) {
            System.out.println("输出" + i);
            if (i == 3){
                //让当前代码进入休眠状态
                Thread.sleep(3000);
            }
        }
    }

线程安全

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

public class Account {
    private double money;

    public Account() {
    }

    public Account(double money) {
        this.money = money;
    }
    public void drawMoney(double money) {
        //先判断是谁来取钱
        String name = Thread.currentThread().getName();
        //判断余额是否充足
        if (this.money >= money){
            System.out.println(name + "来取" + money + "元");
            //更新余额
            this.money -= money;
            System.out.println("剩余" + this.money);
        }else{
            System.out.println("余额不足");
        }

    }
    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }
}



public class DrawThread extends Thread{
    private Account acc;
    public DrawThread(Account acc , String name){
        super(name);
        this.acc = acc;
    }

    @Override
    public void run() {
        //取钱
        acc.drawMoney(100000);
    }
}



	public static void main(String[] args) {
        //创建一个公共账户对象
        Account acc = new Account(100000);

        //创建两个线程
        new DrawThread(acc,"小明").start();
        new DrawThread(acc,"小红").start();


    }

线程同步

概述

在这里插入图片描述

在这里插入图片描述

方式一:同步代码块

在这里插入图片描述

		//同步代码块
        synchronized ("heima") {
            //判断余额是否充足
            if (this.money >= money){
                System.out.println(name + "来取" + money + "元");
                //更新余额
                this.money -= money;
                System.out.println(name + "取钱后剩余" + this.money);
            }else{
                System.out.println(name + "来取,余额不足");
            }
        }

在这里插入图片描述

		//同步代码块
        synchronized (this) {
            //判断余额是否充足
            if (this.money >= money){
                System.out.println(name + "来取" + money + "元");
                //更新余额
                this.money -= money;
                System.out.println(name + "取钱后剩余" + this.money);
            }else{
                System.out.println(name + "来取,余额不足");
            }
        }

方式二:同步方法

在这里插入图片描述

public synchronized void drawMoney(double money) {

}

在这里插入图片描述

方式三:Lock锁

在这里插入图片描述

    //使用final修饰:唯一且不可变
    private final Lock lock = new ReentrantLock();

        lock.lock();//上锁
        try {
            if (this.money >= money) {
                System.out.println(name + "来取" + money + "元");
                //更新余额
                this.money -= money;
                System.out.println(name + "取钱后剩余" + this.money);
            } else {
                System.out.println(name + "来取,余额不足");
            }
        } finally {
            //使用finally,避免上面代码出bug,无法执行解锁操作
            lock.unlock();//解锁
        }

线程通信

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

案例

    public static void main(String[] args) {
        Account acc = new Account("123",0);

        new Draw(acc,"小明").start();
        new Draw(acc,"小红").start();


        new Deposit(acc,"亲爹").start();
        new Deposit(acc,"干爹").start();
        new Deposit(acc,"岳父").start();

    }
public class Account {
    private String idName;
    private double money;

    public Account() {
    }

    public Account(String idName, double money) {
        this.idName = idName;
        this.money = money;
    }

    //存钱
    public synchronized void deposit(double money) {
        try {
            String name = Thread.currentThread().getName();

            if (this.money == 0){
                //存钱
                this.money += money;
                System.out.println(name + "存了" + money + "剩余" + this.money);

                this.notifyAll();//唤醒所有线程
                this.wait();//锁对象,让当前程序进入等待
            }else {
                //不存
                this.notifyAll();//唤醒所有线程
                this.wait();//锁对象,让当前程序进入等待
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    //取钱
    public synchronized void drawMoney(double money) {
        try {
            String name = Thread.currentThread().getName();

            if (this.money >= money){
                //取钱
                this.money -= money;
                System.out.println(name + "取走了" + money + "剩余" + this.money);
                //没钱了

                this.notifyAll();//唤醒所有线程
                this.wait();//锁对象,让当前程序进入等待
            }else {

                this.notifyAll();//唤醒所有线程
                //唤醒别人,等待自己
                this.wait();//锁对象,让当前程序进入等待
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public String getIdName() {
        return idName;
    }

    public void setIdName(String idName) {
        this.idName = idName;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }



}
public class Draw extends Thread{
    private Account acc;

    public Draw (Account acc , String name ){
        super(name);
        this.acc = acc;
    }

    @Override
    public void run() {
        //取钱
        while (true) {
            acc.drawMoney(100000);
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
public class Deposit extends Thread{
    private Account acc;

    public Deposit(Account acc , String name ){
        super(name);
        this.acc = acc;
    }

    @Override
    public void run() {
        //取钱
        while (true) {
            acc.deposit(100000);
            try {
                Thread.sleep(2000);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

线程池

概述

在这里插入图片描述

在这里插入图片描述

线程池实现的API,参数说明

在这里插入图片描述

在这里插入图片描述

//参数一:主线程个数
//参数二:主线程和临时线程总个数
//参数三:临时线程存在时间
//参数四:时间单位(TimeUnit.SECONDS)
//参数五:队列中线程可以等待的个数new ArrayBlockingQueue<>(2)
//参数六:照写Executors.defaultThreadFactory()
//参数七:新任务拒绝策略,默认new ThreadPoolExecutor.AbortPolicy()
ExecutorService pool = new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS, 
new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());

参数七可选择的拒绝策略
在这里插入图片描述

在这里插入图片描述

线程池处理Runnable任务

在这里插入图片描述

//实现Runnable接口
public class MyRunnable implements Runnable{
    @Override
    public void run() {
        for (int i = 0; i < 5; i++) {
            System.out.println(Thread.currentThread().getName() + "线程输出" + i);
        }
        try {
            System.out.println(Thread.currentThread().getName() + "与任务线程绑定");
            Thread.sleep(100000);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

    public static void main(String[] args) {
        //创建线程池对象
        /**   int corePoolSize,
            int maximumPoolSize,
            long keepAliveTime,
            TimeUnit unit,
            BlockingQueue<Runnable> workQueue,
            RejectedExecutionHandler handler
        * */
        ExecutorService pool = new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        //创建Runnable任务对象
        Runnable target = new MyRunnable();

		//线程池执行Runnable任务
        //主线程
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);

        //队列线程
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);
        pool.execute(target);

        //创建临时线程,当线程数量大于主线程和队列线程数量时,临时线程才会被创建
        pool.execute(target);
        pool.execute(target);

//        //不创建,拒绝策略被触发
//        pool.execute(target);
//        pool.execute(target);

        //关闭线程池(开发中一般不使用)
        pool.shutdownNow();//立即关闭,即使任务没有完成。会丢失任务
        pool.shutdown();//会等任务完成后再关闭(建议使用)

    }

线程池处理Callable任务

在这里插入图片描述

//实现Callable接口,可以返回线程执行结果
public class MyCallable implements Callable {
    private int n;
    public MyCallable(int n) {
        this.n = n;
    }

    @Override
    public String call() throws Exception {
        int sum = 0;
        for (int i = 1; i <=n; i++) {
            sum += i;
        }
        return Thread.currentThread().getName() + "和为" + sum;
    }
}

    public static void main(String[] args) throws Exception {

        ExecutorService pool = new ThreadPoolExecutor(3,5,6, TimeUnit.SECONDS,
                new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory()new ThreadPoolExecutor.AbortPolicy());

        //把Callable任务交给线程池处理
        //Callable target = new MyCallable(100);
        //Future<String> f1 = pool.submit(target);
        Future<String> f1 = pool.submit(new MyCallable(100));

		//得到线程执行结果
		//String rs = f1.get();
		//System.out.println(rs);
        System.out.println(f1.get());



    }

Executors工具类实现线程池

在这里插入图片描述

    public static void main(String[] args) {
        //创建固定线程数量的线程池
        ExecutorService pool = Executors.newFixedThreadPool(3);

		//线程池执行Runnable任务
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());
        pool.execute(new MyRunnable());//已经没有多余线程

    }

在这里插入图片描述

在这里插入图片描述

定时器

在这里插入图片描述

方式一:Timer

在这里插入图片描述

    public static void main(String[] args) {
        //创建Timer定时器
        Timer timer = new Timer();
        //调用方法处理定时任务
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行一次");
                try {
                    Thread.sleep(10000);//如果前一个线程睡眠,会影响后面线程的执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }                
            }
        },3000,2000);//等待多久开始,此后每次间隔多久

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行一次");
            }
        },3000,2000);

    }

方式二:ScheduledExecutorService----更常用

在这里插入图片描述

    public static void main(String[] args) {
        //创建ScheduledExecutorService线程池,做定时器
        ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);

        //开启定时任务
        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行AAA");
                try {
                    Thread.sleep(10000);//即使前一个线程睡眠,也不会影响后面线程的执行
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        },0,2, TimeUnit.SECONDS);//开始时间,间隔时间,时间单位

        pool.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + "执行BBB");
            }
        },0,2, TimeUnit.SECONDS);
    }

线程并发、并行

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

线程的生命周期

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

网络编程

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

网络通信三要素

在这里插入图片描述

IP地址

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

IP地址操作类–InetAddress

在这里插入图片描述

        //获取本机地址对象
        InetAddress ip1 = InetAddress.getLocalHost();
        System.out.println(ip1);
        System.out.println(ip1.getHostAddress());
        System.out.println(ip1.getHostName());

        //根据域名获取ip对象
        InetAddress ip2 = InetAddress.getByName("www.baidu.com");
        System.out.println(ip2.getHostAddress());
        System.out.println(ip2.getHostName());

        //获取公网ip对象
        InetAddress ip3 = InetAddress.getByName("39.156.66.14");
        System.out.println(ip3.getHostAddress());
        System.out.println(ip3.getHostName());

        //判断是否联通
        System.out.println(ip3.isReachable(5000));

端口号

在这里插入图片描述

在这里插入图片描述

协议

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

UDP通信

在这里插入图片描述

快速入门----一发一收

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

一发一收

    public static void main(String[] args) throws Exception {
        System.out.println("============客户端=============");
        //创建发送端对象,发送端自带端口
        DatagramSocket socket = new DatagramSocket();

        //创建一个数据包对象封装数据
        /*
        public DatagramPacket(byte buf[], int length,
        InetAddress address, int port)
        参数一;要发送的数据字节数组
        参数二:要发送的数组长度
        参数三:接收端的主机IP地址
        参数四:接收端的端口
        */
        byte [] buffer = "我是快乐的小韭菜。".getBytes();
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length,InetAddress.getLoopbackAddress(),8888);

        //发送数据
        socket.send(packet);

        //关闭管道
        socket.close();
    }
    public static void main(String[] args) throws Exception {
        System.out.println("========服务端=============");
        //创建一个接收端对象,要自己声明端口
        DatagramSocket socket = new DatagramSocket(8888);

        //创建一个数据包对象接收数据
        byte [] buffer = new byte[1024*64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        //等待接收数据
        socket.receive(packet);

        //取出数据
        //接到多少,输出多少
        int len = packet.getLength();
        String rs = new String(buffer,0,len);
        System.out.println("输出:"+ rs);

        //获取发送端的ip和端口
        String ip = packet.getAddress().toString();
        System.out.println("发送端的ip:" + ip);
        int port = packet.getPort();
        System.out.println("发送端的端口:" + port);


        //关闭管道
        socket.close();

    }

多发多收

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在一发一收基础上,增加死循环实现多发多收

    public static void main(String[] args) throws Exception {
        System.out.println("============客户端=============");
        //创建发送端对象,发送端自带端口
        DatagramSocket socket = new DatagramSocket();
        
        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入:");
            String msg = sc.nextLine();

            if ("exit".equals(msg)) {
                System.out.println("离线成功");
                socket.close();
                break;
            }

            //创建一个数据包对象封装数据
            byte[] buffer = msg.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLoopbackAddress(), 8888);

            //发送数据
            socket.send(packet);
        }
    }
    public static void main(String[] args) throws Exception {
        System.out.println("========服务端=============");
        //创建一个接收端对象,要自己声明端口
        DatagramSocket socket = new DatagramSocket(8888);

        //创建一个数据包对象接收数据
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            //等待接收数据
            socket.receive(packet);

            //取出数据
            //接到多少,输出多少
            int len = packet.getLength();
            String rs = new String(buffer, 0, len);
            System.out.println("收到来自:" + packet.getAddress().toString() + ",对方端口是:" + packet.getPort() + "的消息:" + rs);

        }
    }

广播、组播

在这里插入图片描述

广播

在这里插入图片描述

在多发多收基础上,改变接收端的接收ip地址

    public static void main(String[] args) throws Exception {
        System.out.println("============客户端=============");
        //创建发送端对象,发送端自带端口
        DatagramSocket socket = new DatagramSocket();

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入:");
            String msg = sc.nextLine();

            if ("exit".equals(msg)) {
                System.out.println("离线成功");
                socket.close();
                break;
            }

            //创建一个数据包对象封装数据
            byte[] buffer = msg.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length,
                    InetAddress.getByName("255.255.255.255"), 9999);

            //发送数据
            socket.send(packet);
        }
    }
    public static void main(String[] args) throws Exception {
        System.out.println("========服务端=============");
        //创建一个接收端对象,要自己声明端口
        DatagramSocket socket = new DatagramSocket(9999);

        //创建一个数据包对象接收数据
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            //等待接收数据
            socket.receive(packet);

            //取出数据
            //接到多少,输出多少
            int len = packet.getLength();
            String rs = new String(buffer, 0, len);
            System.out.println("收到来自:" + packet.getAddress().toString() + ",对方端口是:" + packet.getPort() + "的消息:" + rs);

        }
    }
组播

在这里插入图片描述

在多发多收基础上,为服务端创建组播ip

        System.out.println("============客户端=============");
        //创建发送端对象,发送端自带端口
        DatagramSocket socket = new DatagramSocket();

        Scanner sc = new Scanner(System.in);
        while (true) {
            System.out.println("请输入:");
            String msg = sc.nextLine();

            if ("exit".equals(msg)) {
                System.out.println("离线成功");
                socket.close();
                break;
            }

            //创建一个数据包对象封装数据
            byte[] buffer = msg.getBytes();
            DatagramPacket packet = new DatagramPacket(buffer, buffer.length,
                    InetAddress.getByName("224.0.1.1"), 9999);

            //发送数据
            socket.send(packet);
        }
    }
    public static void main(String[] args) throws Exception {
        System.out.println("========服务端=============");
        //创建一个接收端对象,要自己声明端口
        MulticastSocket socket = new MulticastSocket(9999);

        //把当前接收端加入到一个组播当中去,绑定对应的组播消息的组播ip
//        socket.joinGroup(InetAddress.getByName("224.0.1.1"));
        socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"),9999),
                NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));


        //创建一个数据包对象接收数据
        byte[] buffer = new byte[1024 * 64];
        DatagramPacket packet = new DatagramPacket(buffer, buffer.length);

        while (true) {
            //等待接收数据
            socket.receive(packet);

            //取出数据
            //接到多少,输出多少
            int len = packet.getLength();
            String rs = new String(buffer, 0, len);
            System.out.println("收到来自:" + packet.getAddress().toString() + ",对方端口是:" + packet.getPort() + "的消息:" + rs);

        }
    }

TCP通信

在这里插入图片描述

快速入门

在这里插入图片描述

在这里插入图片描述

客户端

在这里插入图片描述

    public static void main(String[] args) {
        System.out.println("==========客户端============");
        try {
        //创建Socket通信管道请求服务端的连接
        // public Socket(String host, int port)
        //参数一:服务端的ip地址
        //参数二:服务端的端口
            Socket socket = new Socket("127.0.0.1" , 7777);

            //从Socket通信管道中得到一个字节输出流,负责发送消息
            OutputStream os = socket.getOutputStream();

            //把低级字节输出流包装成打印流
            PrintStream ps = new PrintStream(os);

            ps.print("发送TCP消息");
            ps.flush();//刷新
            
            //一般不用关闭管道,直接关闭会导致通信失败
            //socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
服务端

在这里插入图片描述

在这里插入图片描述

    public static void main(String[] args) {
        System.out.println("==========服务端==============");
        try {
            //注册服务端端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //调用accept方法,等待客户端发送Socket连接请求,建立连接
            Socket socket = serverSocket.accept();
            //从Socket通信管道中得到一个字节输入流,接收信息
            InputStream is = socket.getInputStream();
            //把字节输入流包装成缓冲字符输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //按照行读取消息
            String msg;
            if ((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

多发多收

在这里插入图片描述

    public static void main(String[] args) {
        System.out.println("==========客户端============");
        try {
            //创建Socket通信管道请求服务端的连接
            // public Socket(String host, int port)
            //参数一:服务端的ip地址
            //参数二:服务端的端口
            Socket socket = new Socket("10.31.107.20", 7777);

            //从Socket通信管道中得到一个字节输出流,负责发送消息
            OutputStream os = socket.getOutputStream();

            //把低级字节输出流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc = new Scanner(System.in);
            while (true){
                System.out.println("请输入:");
                String msg = sc.nextLine();
                //发消息
                ps.println(msg);
                ps.flush();
            }


            //一般不用关闭管道,直接关闭会导致通信失败
            //socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        System.out.println("==========服务端==============");
        try {
            //注册服务端端口
            ServerSocket serverSocket = new ServerSocket(7777);
            //调用accept方法,等待客户端发送Socket连接请求,建立连接
            Socket socket = serverSocket.accept();
            //从Socket通信管道中得到一个字节输入流,接收信息
            InputStream is = socket.getInputStream();
            //把字节输入流包装成缓冲字符输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

在这里插入图片描述

同时接收多个客户端消息

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

    public static void main(String[] args) {
        System.out.println("==========客户端============");
        try {
            //创建Socket通信管道请求服务端的连接
            // public Socket(String host, int port)
            //参数一:服务端的ip地址
            //参数二:服务端的端口
            Socket socket = new Socket("10.31.107.20", 7777);

            //从Socket通信管道中得到一个字节输出流,负责发送消息
            OutputStream os = socket.getOutputStream();

            //把低级字节输出流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc = new Scanner(System.in);
            while (true){
                System.out.println("请输入:");
                String msg = sc.nextLine();
                //发消息
                ps.println(msg);
                ps.flush();
            }

            //一般不用关闭管道,直接关闭会导致通信失败
            //socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) {
        System.out.println("==========服务端==============");
        try {
            //注册服务端端口
            ServerSocket serverSocket = new ServerSocket(7777);

            //定义一个死循环由主线程负责,不断的接收客户端的Socket管道连接
            while (true) {
                //每接收到一个客户端的管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();
                //创建独立线程处理socket
                new ServerReaderThread(socket).start();

            }
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
public class ServerReaderThread extends Thread{
    private Socket socket;
    public ServerReaderThread(Socket socket){
        this.socket = socket;
    }
    @Override
    public void run() {
        try {
            //从Socket通信管道中得到一个字节输入流,接收信息
            InputStream is = socket.getInputStream();
            //把字节输入流包装成缓冲字符输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了");
        }
    }
}

使用线程池优化

在这里插入图片描述

在这里插入图片描述

    public static void main(String[] args) {
        System.out.println("==========客户端============");
        try {
            //创建Socket通信管道请求服务端的连接
            // public Socket(String host, int port)
            //参数一:服务端的ip地址
            //参数二:服务端的端口
            Socket socket = new Socket("10.31.107.20", 7777);

            //从Socket通信管道中得到一个字节输出流,负责发送消息
            OutputStream os = socket.getOutputStream();

            //把低级字节输出流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc = new Scanner(System.in);
            while (true){
                System.out.println("请输入:");
                String msg = sc.nextLine();
                //发消息
                ps.println(msg);
                ps.flush();
            }

            //一般不用关闭管道,直接关闭会导致通信失败
            //socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    } 
    //创建一个静态线程池
    private static ExecutorService pool = new ThreadPoolExecutor(3,5,6,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());


    public static void main(String[] args) {
        System.out.println("==========服务端==============");
        try {
            //注册服务端端口
            ServerSocket serverSocket = new ServerSocket(7777);

            //定义一个死循环由主线程负责,不断的接收客户端的Socket管道连接
            while (true) {
                //每接收到一个客户端的管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();

                System.out.println(socket.getRemoteSocketAddress() + "上线了");

				//想要使用线程池,必须封装成任务对象,线程才能执行
                //把socket管道封装成任务对象
                Runnable target = new ServerReaderRunnable(socket);
                //线程池执行任务
                pool.execute(target);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
public class ServerReaderRunnable implements Runnable{
    private Socket socket;
    public ServerReaderRunnable (Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //从Socket通信管道中得到一个字节输入流,接收信息
            InputStream is = socket.getInputStream();
            //把字节输入流包装成缓冲字符输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);
            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了");
        }
    }
}

在这里插入图片描述

及时通信

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

public class Demo1 {
    public static void main(String[] args) {
        System.out.println("==========客户端============");
        try {
            //创建Socket通信管道请求服务端的连接
            // public Socket(String host, int port)
            //参数一:服务端的ip地址
            //参数二:服务端的端口
            Socket socket = new Socket("10.31.107.20", 7777);


            //创建一个独立线程专门负责接收消息
            new ClientReaderThread(socket).start();

            //从Socket通信管道中得到一个字节输出流,负责发送消息
            OutputStream os = socket.getOutputStream();

            //把低级字节输出流包装成打印流
            PrintStream ps = new PrintStream(os);

            Scanner sc = new Scanner(System.in);
            while (true) {
                System.out.println("请输入:");
                String msg = sc.nextLine();
                //发消息
                ps.println(msg);
                ps.flush();
            }

            //一般不用关闭管道,直接关闭会导致通信失败
            //socket.close();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class ClientReaderThread extends Thread {
    private Socket socket;

    public ClientReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //从Socket通信管道中得到一个字节输入流,接收信息
            InputStream is = socket.getInputStream();
            //把字节输入流包装成缓冲字符输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null) {
                System.out.println( "收到消息:" + msg);
            }
        } catch (Exception e) {
            System.out.println("服务端把你踢出群聊");
        }
    }
}
public class serverDemo {

    //定义一个静态的集合,储存所有在线的管道
    public static List<Socket> AllOnlineSockets = new ArrayList<>();


    //创建一个静态线程池
    private static ExecutorService pool = new ThreadPoolExecutor(3,5,6,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        System.out.println("==========服务端==============");
        try {
            //注册服务端端口
            ServerSocket serverSocket = new ServerSocket(7777);

            //定义一个死循环由主线程负责,不断的接收客户端的Socket管道连接
            while (true) {
                //每接收到一个客户端的管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();

                System.out.println(socket.getRemoteSocketAddress() + "上线了");

                AllOnlineSockets.add(socket);//管道上线

                //把socket管道封装成任务对象
                Runnable target = new ServerReaderRunnable(socket);
                pool.execute(target);

            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class ServerReaderRunnable implements Runnable{
    private Socket socket;
    public ServerReaderRunnable (Socket socket){
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //从Socket通信管道中得到一个字节输入流,接收信息
            InputStream is = socket.getInputStream();
            //把字节输入流包装成缓冲字符输入流
            BufferedReader br = new BufferedReader(new InputStreamReader(is));
            //按照行读取消息
            String msg;
            while ((msg = br.readLine()) != null){
                System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);

                //把消息进行端口转发给全部客户端socket管道
                sendMsgToAll(msg);

            }
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了");
            serverDemo.AllOnlineSockets.remove(socket);
        }
    }

    private void sendMsgToAll(String msg) throws Exception {
        for (Socket socket : serverDemo.AllOnlineSockets) {
            PrintStream ps = new PrintStream(socket.getOutputStream());
            ps.println(msg);
            ps.flush();
        }
    }
}

模拟BS系统

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

public class BSserverDemo {
    public static void main(String[] args) {
        System.out.println("==========服务端==============");
        try {
            //注册服务端端口
            ServerSocket serverSocket = new ServerSocket(8080);

            //定义一个死循环由主线程负责,不断的接收客户端的Socket管道连接
            while (true) {
                //每接收到一个客户端的管道,交给一个独立的子线程负责读取消息
                Socket socket = serverSocket.accept();
                //创建独立线程处理socket
                new BSserverReaderThread(socket).start();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class BSserverReaderThread extends Thread {
    private Socket socket;
    public BSserverReaderThread(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //浏览器已经与本线程建立Socket管道
            //响应消息给浏览器显示
            PrintStream ps = new PrintStream(socket.getOutputStream());
            //必须响应HTTP协议格式数据,否则浏览器不认识消息
            ps.println("HTTP/1.1 200 OK");//协议类型和版本 响应成功的消息
            ps.println("Content-Type:text/html;charset=UTF-8");//响应的数据类型 文本/网页

            ps.println();//必须发送一个空行

            //响应数据正文
            ps.println("<span style='color:red;font-size:90px'> 《傻逼阿康》 </span>");

            ps.close();

        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了");
        }
    }
}

在这里插入图片描述

//引入线程池优化
public class BSserverDemo {
    //创建一个静态线程池
    private static ExecutorService pool = new ThreadPoolExecutor(3,5,6,
            TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),
            new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) {
        try {
            //注册服务端端口
            ServerSocket ss = new ServerSocket(8080);

            //定义一个死循环由主线程负责,不断接收客户端的Socket管道连接
            while (true) {
                //每接收到一个客户端的管道,交给一个独立的子线程负责读取消息
                Socket socket = ss.accept();
                //创建独立线程处理socket
                pool.execute(new ServerReaderRunnable(socket));
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class ServerReaderRunnable implements Runnable {
    private Socket socket;

    public ServerReaderRunnable(Socket socket) {
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            //浏览器已经与本线程建立Socket管道
            //响应消息给浏览器显示
            PrintStream ps = new PrintStream(socket.getOutputStream());
            //必须响应HTTP协议格式数据,否则浏览器不认识消息
            ps.println("HTTP/1.1 200 OK");//协议类型和版本 响应成功的消息
            ps.println("Content-Type:text/html;charset=UTF-8");//响应的数据类型 文本/网页

            ps.println();//必须发送一个空行

            //响应数据正文
            ps.println("<span style='color:red;font-size:90px'> 《傻逼阿康》 </span>");

            ps.close();
        } catch (Exception e) {
            System.out.println(socket.getRemoteSocketAddress() + "下线了");
        }
    }
}

单元测试

概述

在这里插入图片描述

在这里插入图片描述

快速入门

在这里插入图片描述

public class Server {
    public String loginName(String loginName , String passWord){
        if("admin".equals(loginName) && "123456".equals(passWord)){
            return "登录成功";
        }else {
            return "有误";
        }

    }

    public void selectName(){
        System.out.println(10/0);
        System.out.println("成功");
    }
}
    /*
    测试方法:
    1.必须是公开的 无参数 无返回值的方法
    2.测试方法必须使用Test注解标记
    */

	//有参数方法测试
    @Test
    public void test(){
        Server server = new Server();
        String rs = server.loginName("admin" , "123456");

        //进行预期结束的正确性测试,断言
        Assert.assertEquals("业务登录成功" , "登录成功" ,rs);
    }

	//无参数方法测试
    @Test
    public void selectServer(){
        Server server = new Server();
        server.selectName();
    }

常用注解

在这里插入图片描述

在这里插入图片描述

反射

概述

在这里插入图片描述

获取类对象

在这里插入图片描述
在这里插入图片描述

public class Test {
    public static void main(String[] args) throws Exception {
        //1、Class类中的一个静态方法:forName(全限名:包名+类名)
        Class c = Class.forName("pk1.Test");
        System.out.println(c);

        //2、类名.Class//最常用
        Class c1 = Test.class;
        System.out.println(c1);

        //3、对象.getClass() 获取对象对应类的Class对象
        Test t = new Test();
        Class c2 = t.getClass();
        System.out.println(c2);
    }
}

在这里插入图片描述

获取构造器对象

在这里插入图片描述

在这里插入图片描述

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

    public Student() {
        System.out.println("无参");
    }

    public Student(int age, String name) {
        System.out.println("有参");
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "Student{" +
                "age=" + age +
                ", name='" + name + '\'' +
                '}';
    }
}
    //1、getConstructors()
    //获取全部构造器,只能获取public修饰的构造器
    @Test
    public void getConstructors() {
        //a.获取类对象
        Class c = Student.class;
        //b.提取类中全部由public修饰的构造器对象
        Constructor[] constructors = c.getConstructors();
        //c.遍历所有构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "=====>" + constructor.getParameterCount());//得到参数名称和对应的参数个数
        }
    }


    //2、getDeclaredConstructors()
    //获取全部构造器,无所谓权限
    @Test
    public void getDeclaredConstructors() {
        //a.获取类对象
        Class c = Student.class;
        //b.提取类中全部的构造器对象
        Constructor[] constructors = c.getDeclaredConstructors();
        //c.遍历所有构造器
        for (Constructor constructor : constructors) {
            System.out.println(constructor.getName() + "=====>" + constructor.getParameterCount());
        }
    }


    //3、getConstructor(Class<?>... parameterTypes)
    //获取某个构造器,只能拿public修饰的某个构造器
    @Test
    public void getConstructor() throws Exception {
        //a.获取类对象
        Class c = Student.class;
        //b.定位当个构造器(按照参数定位无参构造器)
        Constructor cons = c.getConstructor();
        System.out.println(cons.getName() + "=====>" + cons.getParameterCount());
    }


    //4、getDeclaredConstructor(Class<?>... parameterTypes)
    //获取某个构造器,无所谓权限
    @Test
    public void getDeclaredConstructor() throws Exception {
        //a.获取类对象
        Class c = Student.class;
        //b.定位当个构造器(按照参数定位无参构造器)
        Constructor cons = c.getDeclaredConstructor();
        System.out.println(cons.getName() + "=====>" + cons.getParameterCount());

        //c.定位某个有参构造器//要知道参数变量类型
        Constructor cons1 = c.getDeclaredConstructor(int.class , String.class);
        System.out.println(cons1.getName() + "=====>" + cons1.getParameterCount());
    }

在这里插入图片描述

    //1、调用构造器得到一个类的对象返回
    @Test
    public void getDeclaredConstructor() throws Exception {
        //a.获取类对象
        Class c = Student.class;
        //b.定位当个构造器(按照参数定位无参构造器)
        Constructor cons = c.getDeclaredConstructor();
        System.out.println(cons.getName() + "=====>" + cons.getParameterCount());

//        //如果遇到构造器被私有,可以暴力反射
//        cons.setAccessible(true);//权限被打开
        Student s = (Student) cons.newInstance();
        System.out.println(s);

        System.out.println("--------------------");

        //c.定位某个有参构造器
        Constructor cons1 = c.getDeclaredConstructor(int.class , String.class);
        System.out.println(cons1.getName() + "=====>" + cons1.getParameterCount());

        Student s1 = (Student) cons1.newInstance(18,"孙悟空");
        System.out.println(s1);

    }

在这里插入图片描述

获取成员变量对象

在这里插入图片描述

在这里插入图片描述

    //1、获取全部的成员变量
    // File[] getDeclaredFields()
    @Test
    public void getDeclaredFields() {
        //a.获取类对象
        Class c = Student.class;
        //b.定位所有成员变量
        Field[] fields = c.getDeclaredFields();
        //c.遍历一下
        for (Field field : fields) {
            System.out.println(field.getName() + "====>" + field.getType());//得到成员变量的名称和类型
        }
    }


    //2、获取某个成员变量getDeclaredField(String name)
    @Test
    public void getDeclaredField() throws Exception {
        //a.获取类对象
        Class c = Student.class;
        //b.定位某个成员变量
        Field f = c.getDeclaredField("age");//申明变量的名称
        System.out.println(f.getName() + "====>" + f.getType());
    }

在这里插入图片描述

    @Test
    public void setField() throws Exception {
        //a.获取类对象
        Class c = Student.class;
        //提取某个成员变量
        Field ageF = c.getDeclaredField("age");

        ageF.setAccessible(true);//暴力打开权限

        //c.赋值
        Student s = new Student();
        ageF.set(s,18);//s.setAge(18)
        System.out.println(s);

        //d.取值
        int age = (int) ageF.get(s);//s.getAge
        System.out.println(age);

    }

在这里插入图片描述

获取方法对象

在这里插入图片描述

在这里插入图片描述

    //1、获取类中所有成员方法对象
    @Test
    public void getDeclaredMethods(){
        //a.获取类对象
        Class c = Dog.class;
        //b.获取全部方法,包括私有
        Method[] methods = c.getDeclaredMethods();
        //c.遍历全部方法
        for (Method method : methods) {
            System.out.println(method.getName() + "返回类型:" + method.getReturnType() + "参赛名称:" + method.getParameterCount()) ;
        }
    }


    //2、获取某个方法对象
    @Test
    public void getDeclaredMethod() throws Exception {
        //a.获取类对象
        Class c = Dog.class;
        //b.提取单个方法对象
        Method m1 = c.getDeclaredMethod("eat");//要申明方法名称//无参对象
        Method m2 = c.getDeclaredMethod("eat",String.class);//有参对象


        //暴力打开权限
        m1.setAccessible(true);
        m2.setAccessible(true);

        //c.触发方法的执行
        Dog d = new Dog();
        //注意:方法如果没有返回结果回来,那么返回的是null
        String result = (String) m1.invoke(d);
        System.out.println(result);

        String result2 = (String) m2.invoke(d,"骨头");
        System.out.println(result2);

    }

在这里插入图片描述

在这里插入图片描述

反射的作用

绕过编译阶段为集合添加数据

在这里插入图片描述

        ArrayList<Integer> list = new ArrayList<>();
        list.add(12);
        list.add(23);

        Class c = list.getClass();

        Method add = c.getDeclaredMethod("add", Object.class);
        boolean rs = (boolean) add.invoke(list,"黑马");
        System.out.println(rs);
        System.out.println(list);
        

在这里插入图片描述

通用框架的底层原理

在这里插入图片描述

public class MybatisUtil {
    //保存任意类型变量
    public static void save(Object obj){
        try (
                //获取打印输出管道,使用完可自动释放资源
                PrintStream ps = new PrintStream(new FileOutputStream("data",true));
        ){
            //获取类对象
            Class c = obj.getClass();

            ps.println("=========" + c.getSimpleName() + "==============");

            //获取全部成员变量
            Field[] f = c.getDeclaredFields();
            //遍历获取成员变量的信息
            for (Field field : f) {
                //获取成员变量的名称
                String name = field.getName();

                //提取本成员变量在obj对象中的值(取值)
                field.setAccessible(true);//暴力打开权限
                String value = field.get(obj) + "";//把该值转为字符串类型
                //将成员变量名称和对应的值输出
                ps.println(name + "=" + value);

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("小红");
        s.setAge(18);
        s.setSex('男');
        s.setClassName("12");
        s.setHobby("游泳");
        MybatisUtil.save(s);

        Teacher t = new Teacher();
        t.setName("王艳梅");
        t.setSex('男');
        t.setSalary(6000);
        MybatisUtil.save(t);

    }

在这里插入图片描述

注解

概述

在这里插入图片描述

在这里插入图片描述

自定义注解

在这里插入图片描述

public @interface book {
    String name();
    String[] authors();
    double price();
}
@book(name="Java",authors = {"黑马"},price = 100)
public class Demo {

    @book(name="Java",authors = {"黑马"},price = 100)
    public static void main(String[] args) {
        
    }
}

在这里插入图片描述

public @interface MyBook {
    String value();//特殊属性
}

@MyBook(value = "JavaSE")
@MyBook("JavaSE")
public class Demo {
}

元注解

在这里插入图片描述

在这里插入图片描述

@Target({ElementType.METHOD,ElementType.FIELD})//元注解
@Retention(RetentionPolicy.RUNTIME)//一直活着,在运行阶段也不消失
public @interface MyTest {

}

注解解析

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface book {
    String value();
    String[] authors();
    double price();
}

public class Demo2 {

    @Test
    public void parseClass(){
        //a.得到类对象
        Class c = BookStore.class;
        //b.判断这个类上是否存在注解
        if (c.isAnnotationPresent(book.class)){
            //c.直接获取该注解对象
            book books = (book) c.getDeclaredAnnotation(book.class);
            System.out.println(books.value());
            System.out.println(Arrays.toString(books.authors()));
            System.out.println(books.price());
        }
    }



    @Test
    public void parseMethod() throws Exception {
        //a.得到类对象
        Class c = BookStore.class;
        //获取类方法对象
        Method m = c.getDeclaredMethod("test");
        //b.判断这个类上是否存在注解
        if (m.isAnnotationPresent(book.class)){
            //c.直接获取该注解对象
            book books = (book) m.getDeclaredAnnotation(book.class);
            System.out.println(books.value());
            System.out.println(Arrays.toString(books.authors()));
            System.out.println(books.price());
        }
    }
}

@book(value = "活着",authors = "余华" ,price = 12)
class BookStore{

    @book(value = "酒国",authors = "莫言" ,price = 112)
    public void test(){

    }
}

junit框架

在这里插入图片描述

@Target({ElementType.METHOD})//元注解
@Retention(RetentionPolicy.RUNTIME)//一直活着,在运行阶段也不消失
public @interface MyTest {

}
public class Demo3 {
    public void test1() {
        System.out.println("=====test1======");
    }

    @MyTest
    public void test2() {
        System.out.println("=====test2======");
    }

    @MyTest
    public void test3() {
        System.out.println("=====test3======");
    }


    public static void main(String[] args) throws Exception {
        Demo3 d = new Demo3();
        //a.获取类对象
        Class c = Demo3.class;
        //获取所有方法对象
        Method[] m = c. getDeclaredMethods();
        //遍历所有方法,判断是否有注解
        for (Method method : m) {
            if (method.isAnnotationPresent(MyTest.class)){
                method.invoke(d);
            }
        }
    }
}

动态代理

概述

在这里插入图片描述

快速入门

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

//接口
public interface Skill {
    void dance();
    void sing();
}

//被代理对象实现接口
public class Star implements Skill{
    private String name;

    public Star(String name) {
        this.name = name;
    }

    @Override
    public void dance() {
        System.out.println(name + "跳得好");
    }

    @Override
    public void sing() {
        System.out.println(name + "唱得好");
    }
}
public class StarProxyInstance {
    //设计一个方法来返回一个明星对象的代理对象
    public static Skill getProxy(Star obj){
        //为这个对象生成一个代理对象
        /*
        newProxyInstance(ClassLoader loader,
                         Class<?>[] interfaces,
                         InvocationHandler h)
        */
        return (Skill) Proxy.newProxyInstance(obj.getClass().getClassLoader(),
                obj.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("收首付款");
                        //method 调用方法对象  args 代表这个方法的参数
                        Object rs = method.invoke(obj,args);
                        System.out.println("收尾款");
                        return rs;
                    }
                });
    }
}

    public static void main(String[] args) {
        //创建一个对象
        Star s = new Star("杨超越");

        //为对象创建一个代理对象
        Skill s2 = StarProxyInstance.getProxy(s);

        s2.dance();
        s2.sing();

    }

动态代理的应用案例:性能分析

在这里插入图片描述

在这里插入图片描述

public interface UserService {
    String login(String loginName,String passWord);
    void deleteUser();
    String selectUser();
    void deleteById(int id);
}

public class UserServiceImpl implements UserService {
    @Override
    public void deleteById(int id) {

        try {
            System.out.println("删除了" + id);
            Thread.sleep(4000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
public class ProxyUnit {
    //通过一个静态方法,为用户业务对象返回一个代理对象
    public static UserService getProxy(UserService obj){
        return (UserService) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long startTime = System.currentTimeMillis();

                        //真正触发执行
                        Object rs = method.invoke(obj,args);

                        long endTime = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法耗时:" + (endTime - startTime) / 1000.0 + "s");
                        return rs;
                    }
                });
    }
}

    public static void main(String[] args) {

        //把用户对象包装成代理对象
        UserService userService = ProxyUnit.getProxy(new UserServiceImpl());
        System.out.println(userService.login("admin", "12345"));
        System.out.println(userService.selectUser());
        userService.deleteUser();
        userService.deleteById(4);

    }

在这里插入图片描述

public class ProxyUnit {
    //使用泛型,可以为任意接口类型的实现类对象做代理
    public static <T> T getProxy(T obj){
        return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        long startTime = System.currentTimeMillis();

                        //真正触发执行
                        Object rs = method.invoke(obj,args);

                        long endTime = System.currentTimeMillis();
                        System.out.println(method.getName() + "方法耗时:" + (endTime - startTime) / 1000.0 + "s");
                        return rs;
                    }
                });
    }
}

XML

概述

在这里插入图片描述

在这里插入图片描述

XML的创建和语法规则

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>

<!-- 注释 -->
<student>
    <name>女儿国国外</name>
    <sex></sex>
    <hobby>唐僧</hobby>
    <info>
        <age>18</age>
        <adder>女儿国</adder>
    </info>
    <sql>
        select * from user where age &lt; 18;
        <![CDATA[
                select * from user where age < 18;
        ]]>
    </sql>
</student>

XML文档约束

在这里插入图片描述

方式一:DTD约束

在这里插入图片描述

//DTD约束文档格式
<!ELEMENT 书架 (+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>

//调用约束文档
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "data.dtd">
<书架>
    <>
        <书名></书名>
        <作者></作者>
        <售价></售价>
    </>
</书架>

在这里插入图片描述

方式二:schema约束

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

XML解析技术

概述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

Dom4J解析XML文件

在这里插入图片描述

在这里插入图片描述

public class Demo {

    @Test
    public void parseXMLData() throws Exception {
        //1、创建一个Dom4j解析器对象,代表整个Dom4j框架
        SAXReader saxReader = new SAXReader();
        //2、把XML文件加载到内存中成为一个Document文件对象
//        Document document = saxReader.read(new File("xml\\xmldata\\hello_world.xml"));//需要通过模块名去定位
        //注意:getResourceAsStream中的/是直接从src目录下拿文件
        InputStream is = Demo.class.getResourceAsStream("/hello_world.xml");
        Document document = saxReader.read(is);

        //3、获取根元素对象
        Element root = document.getRootElement();
        System.out.println(root.getNamespacePrefix());

    }
}

Dom4J解析XML文件中的各种节点

在这里插入图片描述

案例

在这里插入图片描述

<?xml version="1.0" encoding="UTF-8" ?>
<contactList>
    <contact id="1" vip="true">
        <name>  潘金莲  </name>
        <gender></gender>
        <email>panpan@itcast.cn</email>
    </contact>
    <contact id="2" vip="false">
        <name>武松</name>
        <gender></gender>
        <email>wusong@itcast.cn</email>
    </contact>
    <contact id="3" vip="false">
        <name>武大郎</name>
        <gender></gender>
        <email>wuda@itcast.cn</email>
    </contact>
    <user>
    </user>
</contactList>
public class Contact {
    private String name;
    private int id;
    private  boolean vip;
    private char gender;
    private String email;

    public Contact() {
    }

    public Contact(String name, int id, boolean vip, char gender, String email) {
        this.name = name;
        this.id = id;
        this.vip = vip;
        this.gender = gender;
        this.email = email;
    }

    public String getName() {
        return name;
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public boolean isVip() {
        return vip;
    }

    public void setVip(boolean vip) {
        this.vip = vip;
    }

    public char getGender() {
        return gender;
    }

    public void setGender(char gender) {
        this.gender = gender;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "Contact{" +
                "name='" + name + '\'' +
                ", id=" + id +
                ", vip=" + vip +
                ", gender=" + gender +
                ", email='" + email + '\'' +
                '}';
    }
}

public class Demo {

    @Test
    public void parseToList() throws Exception {
        //1、导入框架
        //2、创建SaxReader对象
        SAXReader saxReader = new SAXReader();
        //3、加载XML文件成为文档对象Document对象
        Document document = saxReader.read(Demo.class.getResourceAsStream("/Contacts.xml"));
        //4、先拿根元素
        Element root = document.getRootElement();
        //5、提取contact子元素
        List<Element> contactElms = root.elements("contact");
        //6、准备一个ArrayList集合封装联系人信息
        List<Contact> contacts = new ArrayList<>();
        //7、遍历Contact子元素
        for (Element contactElm : contactElms) {
            //8、每一个子元素都是一个联系人对象
            Contact contact = new Contact();
            contact.setId(Integer.valueOf(contactElm.attributeValue("id")));
            contact.setVip(Boolean.valueOf(contactElm.attributeValue("vip")));
            contact.setName(contactElm.elementTextTrim("name"));
            contact.setGender(contactElm.elementTextTrim("gender").charAt(0));
            contact.setEmail(contactElm.elementText("email"));
            //9、把联系人对象的数据加到List集合
            contacts.add(contact);
        }
        //10、遍历List集合
        for (Contact contact : contacts) {
            System.out.println(contact);
        }
    }
}

XML检索技术:Xpath

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

绝对路径

在这里插入图片描述

public class XpathDemo {

    //1、绝对路径:根元素/子元素/子元素
    @Test
    public void parse01() throws Exception {
        //a.创建解析器对象
        SAXReader saxReader = new SAXReader();
        //b.把XML加载成Document对象
        Document document =
                saxReader.read(XpathDemo.class.getResourceAsStream("/Contacts2.xml"));

        //c.检索全部名称
        List<Node> nameNodes = document.selectNodes("contactList/contact/name");
        for (Node nameNode : nameNodes) {
            Element nameEle = (Element) nameNode;
            System.out.println(nameEle.getTextTrim());
        }
    }
    
}    

相对路径

在这里插入图片描述

public class XpathDemo {

    //2、相对路径:./子元素/子元素   (.代表当前路径)
    @Test
    public void parse02() throws Exception {
        //a.创建解析器对象
        SAXReader saxReader = new SAXReader();
        //b.把XML加载成Document对象
        Document document =
                saxReader.read(XpathDemo.class.getResourceAsStream("/Contacts2.xml"));

        Element root = document.getRootElement();

        //c.检索全部名称
        List<Node> nameNodes = root.selectNodes("./contact/name");
        for (Node nameNode : nameNodes) {
            Element nameEle = (Element) nameNode;
            System.out.println(nameEle.getTextTrim());
        }
    }
    
}    

全文搜索

在这里插入图片描述

public class XpathDemo {

/*
    3、全文搜索:
    //元素  在全文找这个元素
    //元素1/元素2   在全文找元素1下面的一级元素2
    //元素1//元素2  在全文找元素1下面的全部元素2
    */
    @Test
    public void parse03() throws Exception {
        //a.创建解析器对象
        SAXReader saxReader = new SAXReader();
        //b.把XML加载成Document对象
        Document document =
                saxReader.read(XpathDemo.class.getResourceAsStream("/Contacts2.xml"));
        //c.检索数据
//        List<Node> nameNodes = document.selectNodes("//name");
//        List<Node> nameNodes = document.selectNodes("//contact/name");
        List<Node> nameNodes = document.selectNodes("//contact//name");
        for (Node nameNode : nameNodes) {
            Element nameEle = (Element) nameNode;
            System.out.println(nameEle.getTextTrim());
        }
    }
    
}    

属性查找

在这里插入图片描述

public class XpathDemo {

/*
    4、属性查找
    //@属性名称  在全文检索属性对象
    //元素[@属性名称]   在全文检索包含该属性的元素对象
    //元素[@属性名称=值]  在全文检索包含该属性的元素且属性值为该值的元素对象
    */
    @Test
    public void parse04() throws Exception {
        //a.创建解析器对象
        SAXReader saxReader = new SAXReader();
        //b.把XML加载成Document对象
        Document document =
                saxReader.read(XpathDemo.class.getResourceAsStream("/Contacts2.xml"));
        //c.检索数据
        List<Node> nodes = document.selectNodes("//@id");
        for (Node node : nodes) {
            Attribute attr = (Attribute) node;
            System.out.println(attr.getName() + "====>" + attr.getValue());
        }

        //查询name元素(包含id属性的)
//        Node node = document.selectSingleNode("//name[@id]");
        Node node = document.selectSingleNode("//name[@id=888]");
        Element ele = (Element) node;
        System.out.println(ele.getTextTrim());
    }
    
}    

设计模式

工厂模式

在这里插入图片描述

public abstract class Computer {
    private String name;
    private double price;

    public abstract void start();

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

public class Mac extends Computer{
    @Override
    public void start() {
        System.out.println(getName() + "优雅启动");
    }
}

public class HuaWei extends Computer{
    @Override
    public void start() {
        System.out.println(getName()+ "菊花");
    }
}
public class FactoryPattern {

    //定义一个方法,创建对象返回
    public static Computer createComputer (String info){
        switch (info){
            case "mac" :
                Computer c1  =new Mac();
                c1.setName("MacBook pro");
                c1.setPrice(19999);
                return c1;
            case "huawei" :
                Computer c2 = new HuaWei();
                c2.setName("HuaWei pro 16");
                c2.setPrice(59999);
                return c2;
            default:
                return null;
        }
    }
}

public class FactoryDemo {
    public static void main(String[] args) {
        Computer c1 = FactoryPattern.createComputer("huawei");
        c1.start();

        Computer c2 = FactoryPattern.createComputer("mac");
        c2.start();

    }
}

装饰模式

在这里插入图片描述

//父类
public abstract class InputStream {
    public abstract int read();
    public abstract int read(byte[]buffer);
}

//原始类
public class FileInputStream extends InputStream{
    @Override
    public int read() {
        System.out.println("以低性能的方式读取一个字节a");
        return 97;
    }

    @Override
    public int read(byte[] buffer) {
        buffer[0] = 97;
        buffer[1] = 98;
        buffer[2] = 99;
        System.out.println("以低性能的方式读取了一个字节数组:" + Arrays.toString(buffer));
        return 3;
    }
}
//装饰类:继承InputStream 扩展原始类的功能
public class BufferedInputStream extends InputStream{
    private InputStream is;
    public BufferedInputStream(InputStream is){
        this.is = is;
    }
    @Override
    public int read() {
        System.out.println("提供8KB的缓冲区,提高数据性能");
        return is.read();
    }

    @Override
    public int read(byte[] buffer) {
        System.out.println("提供8KB的缓冲区,提高数据性能");
        return is.read(buffer);
    }
}

public class DecoratorDemo {
    public static void main(String[] args) {
        InputStream is = new BufferedInputStream(new FileInputStream());
        System.out.println(is.read());
        System.out.println(is.read(new byte[3]));

    }
}

完结

在这里插入图片描述

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值