java学习之旅

[TOC]

本篇文章更新java系列知识—持续更新中

image-20220211163044997

快捷键速查

ctrl + shift + u 大小写替换
ctrl + alt +t 快速写一些方法,如try catch
alt + insert 
sout  输出
psvm 主函数

day1 java初识

第一个HelloWord程序

/*
这里HelloWord是类名
void main 是方法,也是程序的入口
void 空
main 主函数
*/

class HelloWord{
    public static void main(String[] args){
        
        System.out.println("Hello Word!");

    }
}

首先用 javac helloword.java –>编译为 helloword.class

然后 java helloword 执行(这里注意不要加后缀!)

结果如下:

image-20220211171119785

注意点:

1、java中严格区分大小写

2、要记得更改编辑器的编码方式 要保持编码一致才能运行

3、每一行语句结束必须以;结束

4、注意缩进

5、类名是什么,生成的字节码文件是什么,与原文件名字没有直接关系。

6、当类是公共的,既用public修饰类,类名必须与文件名保持一致

7、一个java文件中可以有多个类,每个类在编译后都会生成一个字节码文件。

标识符

image-20220211210820972

关键字有:

image-20220211210537067

其中const和goto是保留字

规范:

1、见名知意

2、驼峰命名

当变量名 方法名 参数名 由两个或两个单词以上组成时,从第二个单词开始首字母大写

如:userName passWord

3、对常量进行命名时,每个单词的字母都大写,而且单词与单词之间使用_相连

如: MAX_NUM

4、对类进行命名时,对每一个单词的首字母大写

数据类型

基本数据类型(四类八种):

整数型:

​ byte 字节类型 short int long

浮点类型:

​ float 单精度 double 双精度

字符型:

​ char

布尔型:

​ boolean:

​ true false

引用类型数据:字符串 类 接口

常量

字符串常量 浮点类型常量 字符常量 布尔类型常量 内置的常量

“HelloWoerd” 3.14 ‘你’ true Math.PI

变量

在程序执行过程中,其值可以改变的量

三要素:

变量类型 变量名 变量值

如何申明变量?

数据类型+变量名

申明整数类型变量:

byte b; long 1;

同理可生成

float f; double d; char c; String s;

在方法内的变量 申明后要赋值才能使用

变量的实质就是申请内存

day2 java基础语法

进制转换:

class Sakura{
        public static void main(String [] args){
            System.out.println(666);   //十进制
            System.out.println(0b1010011010); //二进制  0b开头
            System.out.println(01232);  //八进制 0开头
            System.out.println(0x29a); //十六进制 0x开头
    
        }
}

输出结果:

image-20220212154216121

计算机存储单位

image-20220212154344804

1 byte = 8 bit; 没有符号的范围: 2^8-1 有符号(第一位做符号位): -128 - 127

image-20220212160938532

整数类型 注意:

1、整数类型,默认的数据类型是int

2、错误:不兼容的类型:从int转换到byte可能有损失

当我们赋的值在byte或者short的范围内则不会有变化

但是当赋的值不在byte或者short的范围内则会将此值作为int类型处理
3、错误:过大的整数:2222222222

生命long类型数值的时候,要在数值的末尾+L

浮点类型 注意:

1、浮点类型 默认的数据类型是double

2、不兼容的类型:从double转换到float可能会有损失

申明float类型的数据 要在数值的末尾 + F

float f =3.14F

3、浮点类型底层采用的是科学计数法方式

4、小数底层存储方式与整数不同 有符号位 指数位 整数位

5、小数不能精确的表示一个值 (如果要精确的表示需要用到bigdecimal)

计算机如何存储数据

image-20220212172832527

image-20220212172817453

image-20220212173056936

image-20220212173119494

自动类型提升

基本类型数据转换:

1、自动类型提升

小的数据类型 可以自动转换为大的数据类型

int d = 3;
double f = d;

2、强制类型转换

错误:不兼容的类型,从double转换到int可能会有损失

强制转换的公式:

小的数据类型 标识符 = (小的数据类型)大的数据类型

double d = 3.14;
int num = (int)d;

特殊情况

class Sakura{
        public static void main(String [] args){
            int a = 200;
            byte b = (byte)a;
            System.out.println(b);
        }
}

image-20220212221045664

为什么这里是-56呢?

首先我们知道 int是四个字节,而byte只有一个字节,200的二进制数为 11001000

刚好byte可以全部接受,但是byte第一位是符号位,首位是1,所以是负数,计算机的存储方式是以补码的形式存储。11001000—>10110111(反码)—>10111000(补码)

转化为十进制就是-56

image-20220212221721358

运算符

image-20220212222704014

image-20220212222746808

注意:

1、整数相除,不保留小数

2、如果想要显示小数,使用浮点类型计算

3、 byte与byte short与short char与char 做运算,或者他们之间混合运算,则结果会变为int类型

image-20220212225720878

使用赋值运算符是不会发生类型转换的

image-20220212230210588

逻辑运算符

image-20220213150338148

运算符优先级

image-20220213150648548

day3 流程控制语句

输入语句 scanner

import java.util.*;
class InputTest{
    public static void main(String [] args){
            Scanner input = new Scanner(System.in);
            // 创建input对象, "input"是变量,可为任意值
            // System.in 输入流 
            // 输入数据必须与接受类型匹配,不然会报错 如下图
            //Scanner类型没有提供返回char类型数据的方法
            /*
            可以采用 字符串.charAt(0);   0代表字符串内第一个字符,1代表第二个......
            char cc = "你好".charAt(0);
            System.out.println(cc);   ---你
            */
            System.out.println("请输入你的年龄");
            int age = input.nextInt();
            System.out.println("你的年龄是"+age);
            System.out.println("请输入你的身高");
            double height = input.nextDouble();
            System.out.println("你的身高是"+height);
            System.out.println("请输入你的姓名");
            String name = input.next();
            System.out.println("你的姓名是"+name);
        
    }
    
}

image-20220219224259748

next与nextLine

键盘输入一个地址

/*
1、导包
2、创建对象
3、对象调方法
*/
import java.util.*;
class InputTest{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        System.out.println("您的地址是");
        String address = input.next();
        System.out.println("您的地址是"+address);
    }
    
}

注意:
next()无法接受 空格之后的内容

image-20220220223643121

此时我们可以用nextLine(可以接受整行内容)

String address = input.nextLine();

image-20220220223819952

nextLine存在一些问题:

import java.util.*;
class InputTest{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
         System.out.println("您的身高是");
        double height = input.nextDouble();
        System.out.println("您的身高是:"+height);
        System.out.println("您的地址是");
        String address = input.nextLine();
        System.out.println("您的地址是:"+address);
    }
}

当代码如上时,运行程序会出现以下后果:

image-20220220224758917

我们发现第二个输出直接结束了,这是因为nextLine遇到回车,会误认为代码已经结束了。

解决办法:

在中间加入一个

input.nextLine();

来接受回车

image-20220220225008607

image-20220220225108040

这样问题就解决了

if单分支

/*
if分支:
    if单分支
        if(boolean表达式){
            分支内容
        }
*/
import java.util.*;
class IfTest{
    public static void main(String [] args){
        Scanner in = new Scanner(System.in);
        System.out.println("请输入您的年龄");
        int age = in.nextInt();
        if(age >= 18){
            System.out.println("您已经成年,可以上网了");
        }
        if(age < 18){
            System.out.println("您还没有成年,please go out!");
        }    
    }
}

image-20220220231710122

小习题-闰年的标准

闰年的标准(两者满足其一即可):

1、能被4整除,不能被100整除

2、能被400整除

代码功能:

输入一个数判断是否是闰年

import java.util.*;
class RunYears{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        System.out.println("请输入一个年份:");
        int years = input.nextInt();
        if((years%4==0&&years%100!=0)||(years%400==0))
            System.out.println(years+"是闰年!");
    }
}

image-20220220233501106

if双分支

image-20220220233824314

求三个数中的最大值

import java.util.*;
class MaxNum{
    public static void main(String [] args){
        int a = 50;
        int b = 999;
        int c = 12;
        if(a > b){
            if(a > c){
                System.out.println("a是三个数中的最大值");
            }else{
                System.out.println("c是三个数中的最大值");
            }
        
        }else{
            if(b < c){
                System.out.println("c是三个数中的最大值");
            }else{
                System.out.println("b是三个数中的最大值");
            }
            
        }
    }
    
}

image-20220221001754310

if多分支

image-20220221002157818

switch

image-20220221002546023

image-20220221003440041

case后面的数据必须与表达式类型一致

循环

满足特定条件反复执行的代码

任何一个标准的循环都有四个条件:

初始化条件

循环条件

循环体

迭代条件

实例:

import java.util.*;
class Repeat{
     public static void main(String [] args){
        int i = 0;
        while(i<10){
            System.out.println("Hello Word");
            i++;
        }
        
    }
    
    }

image-20220221005248322

day4 循环

do while

image-20220221233148427

随机数公式

Math.random(); 返回一个double值 [0.0,1.0]

如果我们要求 m~n的数

公式: (int)(Math.random()*(n-m+1)+m);

for循环

for 循环:
    for(初始化条件;循环条件;迭代条件){
        循环体    
    }

break

image-20220221234457129

continue、return、continue的区别

image-20220221234650112

day5 数组

数组初识

数组: 容器 存储数据

相同类型数据的有序集合

声明一个数组

image-20220222000443403

数组初始化

两种

静态初始化

arr = new int[]{1,2,3,4,5};  
int [] arr1 = new int[]{1,2,3,4,5};//已经指定元素

动态初始化

arr =new int[4]; //没有指定元素
double [] arrDouble = new double[5];

注意:

数组内元素的类型要保持一致

数组元素的访问

int [] arr = {1,2,3};
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2 ]);

数组长度显示

arr.length 表示数组内元素的数量

System.out.println(arr.length);    

获取最后一个元素的巧妙方法

System.out.println(arr[arr.length-1]);

数组的默认初始化

数组声明之后,数据类型不同,数组中就会有不同的默认值

byte 0 short 0 int 0 long 0 double 0.0 float 0.0 char ‘\u0000’ boolean false

引用数据类型默认值都是null String

数组的遍历

1、借用for循环

for(int i = 0;i<(arr.length-1);i++){
            System.out.println(arr[i]);
        }

2、

image-20220222004651762

代码:

import java.util.*;
class ArrayTest{
     public static void main(String [] args){
        int [] arr = {1,2,3,4,5,6,7,8,9};
        for(int i = 0;i<(arr.length-1);i++){
            System.out.println(arr[i]);
        }
        System.out.println("----------------------");
        for(int a :arr){
            System.out.println(a);
    
        }
    }
    }

image-20220222005429006

数组的内存划分

image-20220222221319026

image-20220222221347039

image-20220222221947302

数组名

image-20220222222235753

数组练习

学生成绩

image-20220222222650621

import java.util.*;
class ArrayTest{
    public static void main(String [] args){
        int [] arr = new int[5];
        Scanner input =new Scanner(System.in);
        int scores = 0;
        for(int i = 0;i < 5;i++){
            System.out.println("请输入第"+(i+1)+"个学生的成绩");
            arr[i] = input.nextInt();
            scores = scores+arr[i];
        }
        float ave = scores/5;
        System.out.println("学生的总成绩是:"+scores);
        System.out.println("学生的平均成绩为:"+ave);
        
        for(int i = 0;i < 5;i++){
            System.out.println("第"+(i+1)+"个学生的成绩是"+arr[i]);
        }
    }
    }

image-20220222224720430

数组找最值

image-20220222232917032

import java.util.*;
class ArrayTest{
    public static void main(String [] args){
        int [] arr = {85,958,235,41,-85,69,74,666,854,9644};
        int one = arr[0];
        for(int i = 1;i < 10;i++){
            if(one < arr[i]){
                one = arr[i];
            }else{
                continue;
            }
        }
        System.out.println("找到了最大的钻石,它的克拉是"+one);
    }
    }

image-20220222232950262

冒泡排序

image-20220222233101791

import java.util.*;
class MaoPao{
    public static void main(String [] args){
        int [] arr = {85,958,235,41,-85,69,74,666,854,9644,856,884};
        for(int ele :arr){
            System.out.print(ele+" ");
        }
        System.out.print("-->");
        int tmp = 0;
        for(int j = 0;j< (arr.length-1);j++){
            for(int i = 0;i < (arr.length-1);i++ ){
            if(arr[i] > arr[i+1]){
                tmp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = tmp;
            }else{
                continue;
            }
        }
        }
        for(int ele :arr){
            System.out.print(ele+" ");
        }
    }
    }

image-20220223002739589

优化:

1、专注于处理无序部分

for(int j = 0;j< (arr.length-1-i);j++){

2、解决无效排序

import java.util.*;
class MaoPao{
    public static void main(String [] args){
        int [] arr = {85,958,235,41,-85,69,74,666,854,9644,856,884};
        for(int ele :arr){
            System.out.print(ele+" ");
        }
        System.out.print("-->");
        int tmp = 0;
        for(int j = 0;j< (arr.length-1);j++){
            boolean flag = true;
            for(int i = 0;i < (arr.length-1);i++ ){
            if(arr[i] > arr[i+1]){
                tmp = arr[i];
                arr[i] = arr[i+1];
                arr[i+1] = tmp;
                flag = false;
            }else{
                continue;
            }
        }
        if(flag == true)
            break;
        }
        for(int ele :arr){
            System.out.print(ele+" ");
        }
    }
    }

day6 数组

查找指定元素的下标

import java.util.*;
class MaoPao{
    public static void main(String [] args){
        Scanner input = new Scanner(System.in);
        System.out.println("请输入您要查找的元素:");
        int a = input.nextInt();
        int [] arr = {85,958,235,41,-85,69,74,666,854,9644,856,884};
        int index = 0;
        for(int i = 0;i<arr.length;i++){
            if(a == arr[i]){
                index = i;
                break;
            }else if(i == (arr.length-1)){
                System.out.println("查无此数");
            }
        }
        System.out.println("该元素的下标为"+index);
    }
    }

image-20220224233730725

二维数组的声明

二维数组:存储一维数组的数组

int [][] arr; //推荐
int arr[][];

二维数组的静态初始化

int [][] arr = {{一维数组元素},{一维数组元素},{一维数组元素}}; //方式一
double [][] doubleArr = new double[][]{{一维数组元素},{一维数组元素},{一维数组元素}};
//方式二

二维数组的动态初始化

image-20220224235726620

int [][] arr = new int[5][5];

image-20220225000442619

这种一维数组可以不等长

double [][] doubleArr = new double[3][];
doubleArr[0] = new double[](3.14,6.28);

二维数组的遍历

普通for循环

image-20220225001512124

增强for循环

image-20220225002726883

二维数组内存图

image-20220225224349397

二维数组练习

1
22
333
4444
55555

image-20220225224754924

image-20220225224829329

image-20220225224959416

idea的使用

image-20220225232922084

ctrl z 撤销
ctrl y 取消撤销

idea自带快捷键

以下写出来后+TAB
psvm  写一个main方法
        public static void main(String[] args) {
        
    }
sout  快速输出语句 
 System.out.println();

shift + enter 快速跳到下一行
CTRL D 快速删除
CTRL ALT 下  快速复制
ALT 上/下 快速移动代码
CTRL SHIFT F 格式化代码
CTRL /  快速单行注释
CTRL shift / 快速多行注释

day7 面向对象

面向对象思想概述

image-20220226000438684

image-20220226000448451

类和对象

image-20220226001405530

image-20220226001717468

image-20220226001904683

创建类和对象

image-20220226002820722

类的创建

[权限修饰符] class 类名{
    
}

image-20220226003024771

对象的创建

new 类名();

image-20220226010357542

image-20220226010407353

创建对象内存图

image-20220226011045893

包名相关

image-20220226011739538

包名一般采用公司网址的倒序

com.guigu.项目名

com.guigu.shopping.login

java.lang不需要导包

java.sql 数据库相关

java.io IO流相关

java.net 网络编程相关

java.util 一些核心的工具类

ALT+ENTER 可以自动导包

image-20220228002520958

示例变量内存图

栈:存放局部变量 执行方法也会开辟空间 (存储时先进后出)

本地方法栈: 当执行native方法、c/c++ 存放局部变量、执行方法也会开辟空间

方法区: 类的信息、变量信息、方法信息、常量信息 …

堆:用来存放 对象数组等等 new出来的东西

程序计数器:用于存储下一条指令

image-20220228012112378

类变量(静态变量)

image-20220228160600660

image-20220228162715834

image-20220228163846163

image-20220228164036100

image-20220228161831408

image-20220228162235053

成员变量练习

声明一个圆的图形类

image-20220228164929259

image-20220228170140156

image-20220228170151620

image-20220228170202651

银行账号

image-20220228170813217

image-20220228172650120

image-20220228180754684

两个类

image-20220228181325744

img

img

成员变量练习内存图

image-20220301003149544

方法的初识

image-20220301003317796

image-20220301004501890

image-20220301004612778

image-20220301005234732

形参和实参

image-20220301010731517

image-20220301010415100

image-20220301010426651

返回值

image-20220301011755061

image-20220301012111930

实例方法

image-20220301013731242

image-20220301013553565

image-20220301013625258

day8面向对象

基本类型值传递

image-20220301221401587

引用数据类型传递

image-20220301222616500

数组内存图

image-20220301223516746

局部变量

定义到方法中的变量是局部变量,局部变量只在方法中有效

局部变量在使用前必须完成初始化,否则报错

定义到类中的变量是成员变量,成员变量只在类中有效

局部变量在方法调用后,才会进行初始化,当方法执行完毕就会随方法弹栈消失

image-20220301225248322

image-20220301225548707

可变形参

参数的个数可以是任意个 0~n

如何声明?

public static void sum(int...a){}  //三个点

可变形参采用数组存储实参

xxxxxxxxxx public static void sum(double a , int...a){} 

不能存在两个可变参数,且可变参数必须在最后

方法重载

不同的方法可以使用相同的方法名

要求:同一类中,同一方法名,不同的形参列表:数量、顺序、类型

image-20220302000931131

方法调用时会根据不同的数据类型找到最佳匹配的方法

命令行参数

idea

image-20220302003110469

命令行

class Sakura{
    public static void main(String [] args){
        for(String ele:args){
            System.out.println(ele);
        }
    }
}

image-20220302003703283

静态导入

导入一个类中的所有静态资源

image-20220302004244597

image-20220302003831636

递归

image-20220302225312848

image-20220302235022144

对象类型数组

image-20220303001402384

封装的概念及四个权限修饰符的概念

image-20220303215651821

image-20220303215810126

image-20220303220134500

image-20220303220910747

属性的简单封装

image-20220303221632106

image-20220303221931211

day9面向对象

构造器

可以快速给成员变量赋值

image-20220303231205347

创建类

image-20220303231339865

构造

image-20220303231528049

每一个类都会有一个无参构造器,但是当声明有参构造器后,默认无参构造器就会消失,这时候如果再写

Student s = new Student();

就会报错。所以建议自定义类都再提供一个无参构造器。

使用构造器创建对象

image-20220303232035228

image-20220303233229581

对属性的封装

image-20220304004650481

要对用户的信息进行校验

image-20220304005044933

练习

image-20220304005720701

//Staff.java

package com.sakura.staff;

public class Staff {
    private int num;
    private char sex;
    private double salary;
    private String name;
    public Staff(int a, String b, char c, double d){
        this.num = a;
        this.name = b;
        this.sex = c;
        this.salary = d;
    }
    public Staff(){}
    void setinfo(int a,String b,char c,double d){
        this.num = a;
        this.name = b;
        this.sex = c;
        this.salary = d;
    }
    void getinfo(){
        System.out.println("num = " + num);
        System.out.println("name = " + name);
        System.out.println("sex = " + sex);
        System.out.println("salary = " + salary);
    }
}
//Test.java

package com.sakura.staff;

public class Test {
    public static void main(String[] args) {
        Staff num1 = new Staff();
        num1.setinfo(123,"sakura",'男',20000);
        num1.getinfo();
        Staff num2 = new Staff(666,"Alice",'女',10000);
        num2.getinfo();
    }
}

image-20220304012001796

标准javabean

image-20220304093001246

image-20220304093017092

继承

image-20220304093913672

image-20220304094152414

1、使用继承要借用关键字extends

2、语法结构

[权限修饰符] 子类 extends 父类{}

3、当子类继承父类后就可以使用父类的资源

范例:

父类:

package com.sakura.jicheng;

public class Animal {
    private String name;
    private int age;
    void setname(String name){
        this.name = name;
    }
    void setAge(int age){
        this.age = age;
    }
    void eat(){
        System.out.println(this.name+"正在吃饭");
    }
    int getinfo_age(){
        return this.age;
    }
    String getinfo_name(){
        return this.name;
    }
}

Cat类

package com.sakura.jicheng;

public class Cat extends Animal{
    void miao(){
        System.out.println("miao~miao~miao~");
    }
}

Dog类

package com.sakura.jicheng;

public class Dog extends Animal{
    void wang(){
        System.out.println("wang wang wang");
    }
}

Test类

package com.sakura.jicheng;

public class Test {
    public static void main(String[] args) {
        Cat cat = new Cat();
        cat.setAge(8);
        cat.setname("咪咪");
        System.out.println(cat.getinfo_age());
        System.out.println(cat.getinfo_name());
        cat.miao();
        Dog dog = new Dog();
        dog.setAge(10);
        dog.setname("大白");
        System.out.println(dog.getinfo_age());
        System.out.println(dog.getinfo_name());
        dog.wang();
    }
}

image-20220304130800705

当出现同名变量时:this与super

image-20220304131840347

super代表从父类继承下来的资源

image-20220304132237877

继承资源的查找

父类的方法不能满足子类需求时,要进行方法重写

子类在使用资源时,优先在本类中查找,当本类中没有时,才去父类中查找,一点一点向上找,直到找到object类

object类是所有类的父类

image-20220304145340962

方法的重写

1、当子类重写父类的方法时,访问权限不能比父类的访问权限更加严格,要>=父类的访问权限

2、返回值类型

当父类的返回类型是基本数据类型时,则子类必须与父类保持一致

当父类的返回类型是引用数据类型时,则子类可以是返回父类,也可以是返回子类

3、方法重写时,子类的形参必须与父类的形参保持一致,否则就相当于在子类中新增一个方法

4、子类不能抛出比父类更大的异常

this详解

this可以区分局部变量和成员变量

this可以调用本类中的构造器(是根据数据类型来匹配的,而不是形参名)

image-20220304152113902

调用另一个构造器时,this必须放在本构造器首行,如本例中

this(name,age,salary);

就在首行

一般都是多参调少参。在本类中,this可省略

super详谈

image-20220304153656976

每一个构造器首行都会有一个默认的隐藏的super,调用父类无参的构造器

image-20220304154053753

当这种情况的时候,super是在少参的构造器中,第二个参数构造器的super()自动消失了

image-20220304155540813

可以使用super()调用父类有参的构造器

可以使用super.调用父类的属性和方法

成员变量的赋值方法

image-20220304160521490

image-20220304160500362

image-20220304160942707

代码块用 {}包裹

当是这种静态代码块时,代码块只执行一次

image-20220304160839692

image-20220304160744120

image-20220304160752027

静态代码块:用于给静态变量进行赋值

静态代码只会执行一次,再次创建n个对象也不会执行。也是先于构造器执行

给成员变量赋值方式:

1.默认值

2.直接赋值

3.代码块赋值

4.get/set赋值

5、构造器赋值

静态变量不建议采用使用构造器赋值,因为它是属于类的,可以直接 类名.属性进行赋值

day10 面向对象

类的初始化

image-20220306000154596

image-20220306001804012

image-20220306002346773

当有子类的初始化时,会先对父类进行初始化,再初始化子类

类的初始化不含子类

image-20220306010601437

image-20220306010614896

实例初始化不含子类

image-20220306011526112

image-20220306011757666

每次调用构造器,都会重复执行一次init方法

类的初始化含子类

image-20220306012632684

混合初始化

image-20220306013247338

多态的初识

封装:隐藏内部的实习细节,只对外暴露少量接口,供外界访问

方法:对功能的封装

类:对方法的封装

包:对模块的封装


继承:实现资源的复用

​ 方法属性


多态:一个对象的多种形态

作用:可以让代码更加灵活

image-20220306110018629

多态有两种状态(左边编译时状态 = 右边运行时状态):

1、编译时状态

2、运行时状态

多态创建的对象能够调用什么方法要看编译时状态

image-20220306110650725

image-20220306110802347

示例代码:

Animal类

package com.sakura.duotai;

public class Animal {
    void eat(){
        System.out.println("吃饭啦~~");
    }
}

Cat类

package com.sakura.duotai;

public class Cat extends Animal{
    void eat(){
        System.out.println("猫吃鱼");
    }
    void catchMouse(){
        System.out.println("猫抓老鼠");
    }
}

Dog类

package com.sakura.duotai;

public class Dog {
    void eat(){
        System.out.println("狗吃骨头");
    }
    void lookHome(){
        System.out.println("狗看家");
    }
}

当我们用Animal类去new一个子类对象时,就是多态的一种体现

image-20220306113022606

image-20220306113038273

如图,输出的是猫重写的eat方法

但当我们尝试调用cat中其它方法时,就会报错

image-20220306113233339

Animal a = new Cat();
/**这里的Animal a 就是编译时状态 
new cat(); 是运行时状态
多态创建的对象能够调用什么方法要看编译时状态,代码跑起来时对象是谁,要看运行时状态**/

多态的作用一节省代码量

package com.sakura.duotai1;

public class Programmer {
    void eat(){
        System.out.println("程序员 干饭");
    }
}
class Chinese extends Programmer{
    void eat(){
        System.out.println("中国人使用筷子吃饭");
    }
    void act(){
        System.out.println("中国人会功夫");
    }
}
class India extends Programmer{
    void eat(){
        System.out.println("印度人使用手吃饭");
    }
    void act(){
        System.out.println("印度人摩托车玩的贼6");
    }
}
class European extends Programmer{
    void eat(){
        System.out.println("欧洲人使用刀叉吃饭");
    }
    void act(){
        System.out.println("欧洲人喜欢极限运动");
    }
}
package com.sakura.duotai1;

public class Test {
    public static void main(String[] args) {
        Chinese chinese = new Chinese();
        India india = new India();
        European european = new European();
        showEat(chinese);
        showEat(india);
        showEat(european);
    }
    public static void showEat(Programmer programmer){
        programmer.eat();
    }
}

image-20220306120428090

这样写,节省了很多代码量

由于这里的Programmer programmer 是形参,所以会有

Programmer programmer = chinese/india/european;

满足父类的引用指向子类的对象

多态作用二存储不同类型数据

package com.sakura.duotai2;

public class Animal {
    void eat(){
        System.out.println("动物吃饭");
    }
}
class Dog extends Animal{
    void eat(){
        System.out.println("猫吃鱼");
    }
}
class Cat extends Animal{
    void eat(){
        System.out.println("狗吃肉");
    }
}
package com.sakura.duotai2;

public class Test {
    public static void main(String[] args) {
        int [] arr = {10,20,30};//这是一个数组它只能存储同一种类型数据
        Animal [] aniarr = new Animal[2];
        Dog dog = new Dog();
        Cat cat = new Cat();
        aniarr[0] = dog;
        aniarr[1] = cat;
        for(Animal a:aniarr){
            a.eat();
        }
    }
}

此处的cat和dog是不同类型的示例对象,但是都放在了同一个数组

多态应用三方法的返回值

示例代码:

Programmer.java

package com.sakura.duotai3;

public class Programmer {
    void work(){
        System.out.println("程序员 写代码");
    }
}
class Chinese extends Programmer{
    void work(){
        System.out.println("中国 程序员写代码");
    }
}
class India extends Programmer{
    void work(){
        System.out.println("印度 程序员写代码");
    }
}
class European extends Programmer{
    void work(){
        System.out.println("欧洲 程序员写代码");
    }
}

Guigu.java

package com.sakura.duotai3;

public class Guigu {
    public static Programmer produce_Grammer(String country){
        if("中国".equals(country)){
            return new Chinese();
        }else if("印度".equals(country)){
            return new India();
        }else if("欧洲".equals(country)){
            return new European();
        }
        return null;
    }
}

Test.java

package com.sakura.duotai3;

import java.util.Scanner;
public class Test {
    public static void main(String[] args) {
        System.out.println("请输入您需要的程序员国家:");
        Scanner input = new Scanner(System.in);
        String country = input.next();
        Programmer programmer = Guigu.produce_Grammer(country);
        if (programmer != null) {
            programmer.work();
        } else {
            System.out.println("还没有此国家程序员");
        }
    }
}

image-20220306153850750

image-20220306153923126

多态的练习一

image-20220306154354906

Traffic.java

package com.sakura.duotai4;

public class Traffic {
    public void drive(){
        System.out.println("交通工具通行");
    }
}
class Car extends Traffic{
    public void drive(){
        System.out.println("汽车奔驰在马路上");
    }
}
class Bike extends Traffic{
    public void drive(){
        System.out.println("自行车在马路上缓慢的走着");
    }
}
class Truck extends Traffic{
    public void drive(){
        System.out.println("货车满载着货物不快不慢的开着");
    }
}

Test.java

package com.sakura.duotai4;

public class Test {
    public static void main(String[] args) {
        Traffic [] trarr =new Traffic[3];
        trarr[0] = new Car();
        trarr[1] = new Bike();
        trarr[2] = new Truck();
        for(Traffic a:trarr){
            a.drive();
        }
    }
}

image-20220306155645389

多态的练习二

image-20220306155901154

示例代码:

Employee.java

package com.sakura.duotai5;

public class Employee {
    private String name;
    public String getName() {
        return name;
    }

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

    public double earning(){
        return 0;
    }
    public String getinfo(){
        return "姓名是:"+name+" ,实发工资"+earning();
    }
    public Employee(){};

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

SalaryEmployee.java

package com.sakura.duotai5;

public class SalaryEmployee extends Employee{
    private double salary;
    private int workday;
    private int offday;
    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public int getWorkday() {
        return workday;
    }

    public void setWorkday(int workday) {
        this.workday = workday;
    }

    public int getOffday() {
        return offday;
    }

    public void setOffday(int offday) {
        this.offday = offday;
    }
    public SalaryEmployee(){};

    public SalaryEmployee(double salary, int workday, int offday,String name) {
        super(name);
        this.salary = salary;
        this.workday = workday;
        this.offday = offday;
    }

    @Override
    public double earning() {
        return (getSalary()-getSalary()/getWorkday()*getOffday());
    }
}

Manager.java

package com.sakura.duotai5;

public class Manager extends SalaryEmployee{
    private double part;
    public double earning(){
        return (getSalary()-getSalary()/getWorkday()*getOffday()*(1+part));
    }
    public Manager(){}

    public Manager(double salary, int workday, int offday, String name, double part) {
        super(salary, workday, offday, name);
        this.part = part;
    }
}

HourEmployee.java

package com.sakura.duotai5;

public class HourEmployee extends Employee{
    private int hours;
    private int hourmoney;

    public int getHours() {
        return hours;
    }

    public void setHours(int hours) {
        this.hours = hours;
    }

    public int getHourmoney() {
        return hourmoney;
    }

    public void setHourmoney(int hourmoney) {
        this.hourmoney = hourmoney;
    }
    public double earning(){
        return getHours()*getHourmoney();
    }
    public HourEmployee(){}
    public HourEmployee(String name, int hours, int hourmoney) {
        super(name);
        this.hours = hours;
        this.hourmoney = hourmoney;
    }
}

Test.java

package com.sakura.duotai5;

public class Test {
    public static void main(String[] args) {
        Employee [] employee = new Employee[5];
        SalaryEmployee s1 = new SalaryEmployee(10000,20,5,"蜡笔小新");
        SalaryEmployee s2 = new SalaryEmployee(15000,20,5,"张伟");
        HourEmployee h1 = new HourEmployee("苦逼打工人",30,15);
        HourEmployee h2 = new HourEmployee("小王",50,30);
        Manager m1 = new Manager(20000,22,3,"霸道总裁",0.9);
        employee[0] = s1;
        employee[1] = s2;
        employee[2] = h1;
        employee[3] = h2;
        employee[4] = m1;
        for(Employee a:employee){
            System.out.println(a.getinfo());
        }
    }
}

image-20220306213734875

向下转型

image-20220306214039535

多态的向上转型和向下转型都是都是针对于编译时类型 运行时类型从始至终不会发生改变

父类的引用指向子类的示例 就是向上转型(弊端:无法使用子类独有资源):

Animal ani = new Cat();

向下转型:

使用子类自己独有的资源时 down casting

image-20220306215605369

类似于强制类型转换

向下转型前提:已经完成了向上转型

instanceof

判断左边的对象是否属于右边类型

image-20220306220002482

image-20220306220011415

image-20220306221125721

image-20220306222229248

day11

非虚方法

image-20220307222921425

image-20220307222347375

native关键字

image-20220307224544250

image-20220307224944403

image-20220307225003737

final关键字

image-20220307225623364

image-20220307230404578

Object类

image-20220307230702220

to_string

image-20220307231033786

image-20220307231050043

image-20220307232014058

原方法

image-20220307232032977

重写后

image-20220307232136187

直接alt+insert添加即可

getClass()

获取运行时类型

image-20220307232536412

image-20220307232551295

finalize

image-20220307233825712

image-20220307233742142

image-20220307233200553

hashcode

用于返回当前对象的hash码

image-20220307234118067

image-20220307234327319

image-20220307234646637

重写hashcode()方法,尽量让不同对象产生的hash码不一样

image-20220307234725681

equals()

image-20220308000837040

equals 只能比较引用类型数据

image-20220307235240218

image-20220308000516442

空指针异常

image-20220308004815978

image-20220308004823230

image-20220308004929031

抽象初识

image-20220309001110049

image-20220309001857256

image-20220309003126201

image-20220309002153677

抽象注意点

image-20220309003553843

image-20220309003622175

image-20220309004543157

接口初识

如何声明接口:

接口:定义规范

image-20220309010955198

image-20220309010752566

image-20220309010914703

接口也有多态

image-20220309011210309

image-20220309011357791

注意:

接口中的抽象方法默认被 public abstract 修饰

image-20220309011610133

接口中的全局静态常量默认被

image-20220309011859135

这三个修饰

一个类可以实现多个接口

image-20220309012134974

一个类实现接口后,如果不想实现接口中的抽象方法,则自己必须变为抽象类

image-20220309012443711


添加默认方法:

image-20220309012838207

这个方法不是每个实现这个接口的类都必须要重写的,按需使用。比如飞机和小鸟,只有飞机需要加油,小鸟并不需要。

添加静态方法:

image-20220309013126800

image-20220309013720061

接口也可以进行多继承:

image-20220309013858147

一个类可以先继承一个父类,再去实现多个接口,顺序不能改变,必须先继承再改变

image-20220309014202863

接口的非正常情况

image-20220309015249961

image-20220309015303113

这两个接口有重名的方法,当实现的时候就会报错

image-20220309015327271

解决方法:在类中重写 study方法

image-20220309015415696

但是,但我们想要调用接口的study方法该怎么办?

重写study后这样调用:

image-20220309015757108

image-20220309015510568

image-20220309015547202

comparable接口

image-20220309020503383

使用comparable接口完成引用数据类型的比较

image-20220309020938494

需要实现:

image-20220309021013901

重写Comparable

image-20220309021220640

image-20220309021248580

day12 面向对象

comparable接口-内部比较器

image-20220317222648883

package com.sakura.neibu;

public class Test {
    public static void main(String[] args) {
    Person p1 = new Person("李白",40);
    Person p2 = new Person("杜甫",30);
    int i = p1.compareTo(p2);
    if(i>0){
        System.out.println(p1.name+">"+p2.name);
    }else if(i<0){
            System.out.println(p1.name+"<"+p2.name);
        }else {
        System.out.println(p1.name+"="+p2.name);
    }

    }

}

class Person implements Comparable{
    @Override
    public int compareTo(Object o) {
        Person p = (Person)o;

        return this.age-p.age;
    }

    String name;
    int age;

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

image-20220321223505628

Comparator接口-外部比较器

image-20220322223441069

代码范例:

Person.java

package com.sakura.waibu;

public class Person {
    String name;
    int age;
    double salary;

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

    public Person() {
    }

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

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

    public void setSalary(double salary) {
        this.salary = salary;
    }
}

PerSortOfAge.java

package com.sakura.waibu;

import java.util.Comparator;

public class PersonSortOfAge implements Comparator {
    @Override
    public int compare(Object o1, Object o2) {
        Person p1 = (Person)o1;
        Person p2 = (Person)o2;
        return p1.age-p2.age;
    }
}

Test.java

package com.sakura.waibu;

public class Test {
    public static void main(String[] args) {
        Person p1 = new Person("李白",60,6666.55);
        Person p2 = new Person("杜甫",58,8888);
        PersonSortOfAge sortOfAge = new PersonSortOfAge();
        int res = sortOfAge.compare(p1,p2);
        if(res > 0){
            System.out.println(p1.name+">"+p2.name);
        }else if(res < 0){
            System.out.println(p2.name+"<"+p1.name);
        }else {
            System.out.println(p1.name+"="+p2.name);
        }
    }
}

image-20220322225423524

枚举

枚举初识

image-20220322232627649

示例代码:

Season.java

package com.sakura.enum2;

public enum Season {
    SPRING("春暖花开","春天"),
    SUMMER("夏日炎炎","夏天"),
    AUTUMN("秋高气爽","秋天"),
    WINTER("白雪恺恺","冬天");
    private String des;
    private String name;

    Season(String des, String name) {
        this.des = des;
        this.name = name;
    }
    Season() {
    }

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

test.java

package com.sakura.enum2;

public class test {
    String name = "word";
    int num = 200;
    Season season = Season.SPRING;
    public static void main(String[] args) {
        test one =new test();
        System.out.println("one.name = " + one.name);
        System.out.println("one.season = " + one.season.name());
        System.out.println("one.num = " + one.num);
    }
}

image-20220714155112254

枚举结束

使用switch语句来判断是哪个枚举:

TestSwitch.java

package com.sakura.enum2;

public class TestSwitch {
    public static void main(String[] args) {
        Season season = Season.SPRING;
        switch (season){
            case SPRING:
                System.out.println("温暖");
                break;
            case SUMMER:
                System.out.println("炎热");
            case AUTUMN:
                System.out.println("舒适");
                break;
            case WINTER:
                System.out.println("寒冷");
                break;
        }
    }
}

image-20220714160849714

枚举实现接口

Gender.java

package com.sakura.enum3;

public enum Gender implements Run{
    MAN{
        @Override
        public void run() {
            System.out.println("男士 大步走");
        }
    },WOMAN{
        @Override
        public void run() {
            System.out.println("女士 不紧不慢的走");
        }
    };
}
interface Run{
    void run();
}

Test.java

package com.sakura.enum3;

public class Test {
    public static void main(String[] args) {
        Gender people = Gender.MAN;
        people.run();
    }
}

练习

image-20220714222230916

示例代码:

Month.java

package com.sakura.enum4;

public enum Month {
    JANUARY(1,"这是一月"),
    FEBRUARY(2,"这是二月"),
    March(3,"这是三月"),
    APRIL(4,"这是四月"),
    MAY(5,"这是五月"),
    JUNE(6,"这是六月"),
    JULY(7,"这是七月"),
    AUGUST(8,"这是八月"),
    SEPTEMBER(9,"这是九月"),
    OCTOBER(10,"这是十月"),
    NOVEMBER(11,"这是十一月"),
    DECEMBER(12,"这是十二月");
    private int value;
    private String des;

    Month(int value, String des) {
        this.value = value;
        this.des = des;
    }

    Month() {
    }

    @Override
    public String toString() {
        return "Month{" +
                "value=" + value +
                ", des='" + des + '\'' +
                '}';
    }
}

Test.java

package com.sakura.enum4;

import java.util.Scanner;

public class Test {
    public static void main(String[] args) {
        System.out.println("请输入您要获取月份所对应的数字:");
        Scanner input = new Scanner(System.in);
        int num = input.nextInt();
        getByValue(num);
    }
    public static Month getByValue(int value){
        switch (value){
            case 1:
                System.out.println(Month.JANUARY);
                break;
            case 2:
                System.out.println(Month.FEBRUARY);
                break;
            case 3:
                System.out.println(Month.March);
                break;
            case 4:
                System.out.println(Month.APRIL);
                break;
            case 5:
                System.out.println(Month.MAY);
                break;
            case 6:
                System.out.println(Month.JUNE);
                break;
            case 7:
                System.out.println(Month.JULY);
                break;
            case 8:
                System.out.println(Month.AUGUST);
                break;
            case 9:
                System.out.println(Month.SEPTEMBER);
                break;
            case 10:
                System.out.println(Month.OCTOBER);
                break;
            case 11:
                System.out.println(Month.NOVEMBER);
                break;
            case 12:
                System.out.println(Month.DECEMBER);
                break;
        }
        return Month.JANUARY; # 这个地方的return只是为了避免报错,无特殊含义
    }

}

image-20220714223902463

包装类初识

Java提供了两个类型系统,基本类型与引用类型,使用基本类型在于效率,然而当要使用只针对对象设计的API或新特性(例如泛型),那么基本数据类型的数据就需要用包装类来包装。

image-20220714223558341

比如Integer有很多方法

test.java

package com.sakura.wrapper;

public class test {
    public static void main(String[] args) {
        int a = 100;
        System.out.println(Integer.MAX_VALUE);
        System.out.println(Integer.MIN_VALUE);
        String s1 = Integer.toBinaryString(a);
        String s2 =Integer.toHexString(a);
        System.out.println("s1 = " + s1);
        System.out.println("s2 = " + s2);
    }
}

image-20220714225729157

自动装箱和自动拆箱

基本数据类型转化为包装类型数据:

老方法:

方式一:通过构造器

Integer 标识符 = new Integer(基本数据类型);
如: 
int a = 10;
Integer i1 = new Integer(a);

方法二

Integer 标识符 = Integer.valueOf(基本数据类型);
如:
int a = 10;
Integer i2 = Integer.valueOf(a);

新方法:

自动装箱

Integer in = 基本数据类型;
自动装箱底层采用的是 IntegerOf.valueOf(a);

包装类型数据转化为基本类型数据:

Integer i4 = new Integer(20);

方法一:调用包装类对象的 intValue();

int i = i4.intValue();

方法二:自动拆箱

自动将引用数据类型变为基本数据类型

int i =i4;

基本类型与包装类型与字符串之间的转换

1、字符串—>基本数据类型

Integer.parseInt(“字符串纯数字”); 如果不是纯数字,会报异常,NumberFormatException

示例代码:

test.java

package com.sakura.wrapper2;

import java.util.Scanner;

public class test {
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入一个数字:");
        String a = input.next();
        int b = Integer.parseInt(a);
        System.out.println("b = " + b);
    }
}

image-20220715152344679

方法二:

Integer i = new Integer("字符串纯数字");

image-20220715152746653

注意char中没有此类方法:

"AB".charAt(1); 0代表第一个字符,1代表第二个字符

2、基本类型数据转为字符串

方法一:

int a = 10;
String ss = ""+a;

方法二:

int b = 20;
string i = String.valueOf(b);

对应包装类型的缓存区

包装类型数据,只能接受对应的包装类型,不能再采用类型自动提升

image-20220716155808087

包装类型有一个缓存区,超过这个区域,就会去new一个包装类

image-20220716160816365

示例代码:

public class test {
    public static void main(String[] args) {
        Integer a = 100;
        Integer b = 100;
        System.out.println("1----->" + (a==b));
        Integer c = 1000;
        Integer d = 1000;
        System.out.println("2------>"+(c==d));
    }
}

image-20220716161726283

静态内部类

什么是内部类?

将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。

作用:

1.可以打破java单继承的限制
2.在内部类中做更多的功能为外部类服务
3.可以资源的隐藏

特点:

静态内部类可以访问静态外部类资源

静态的属性,静态的方法

修饰:

外部类只能被public和public修饰,内部类无限制

语法结构:

class 外部类名{
    [权限修饰符四种] static [final] class 内部类名{
        
    }
}

非静态内部类

不加static修饰的内部类

class 外部类名{
    [权限修饰符四种] class 内部类名{
        
    }
}

特点:

image-20220901212139028

image-20220901212912590

day13

局部内部类

不是重点

image-20220902214930486

image-20220902222245029

image-20220902230731669

匿名内部类的声明

匿名内部类:没有名字的类

匿名对象:没有名字的对象

方式一:

new 父类(){
    重写父类方法
}
创建了一个子类,但是子类没有名字

方式二:

new 父类(实参列表){
    重写父类方法
}
创建了一个子类,但是子类没有名字

方式三:

new 父接口(){
    重写父类方法
}
创建了一个子类,但是子类没有名字

方式四:

new 父抽象类(){
    重写父类方法
}
创建了一个子类,但是子类没有名字

image-20220903003418869

示例代码:

package com.sakura.innerclass.anosclass;

import org.junit.Test;

interface Run{
    void run();
}

abstract class Animal{
    abstract void eat();
}

public class TestLocal {
    @Test
    public void test01(){
        new Father(){
            @Override
            public void show() {
                System.out.println("this is new show-1()");
            }
        };
    }
    @Test
    public void test02(){
        new Father(30){
            @Override
            public void show() {
                System.out.println("this is new show-2(30)");
            }
        };
    }
    @Test
    public void test03(){
        new Run(){
            @Override
            public void run() {
                System.out.println("this is new Run");
            }
        };

    }
    @Test
    public void test04(){
        new Animal(){
            @Override
            void eat() {
                System.out.println("this is new eat()");
            }
        }
    }

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

    }
    public void show(){
        System.out.println("this is father show(");
    }
}

匿名内部类的使用

image-20220903012609400

package com.sakura.innerclass.anosclass;

import org.junit.Test;

interface Fly{
    void fly();
}

public class TestLocal2 {
    @Test
    public void test03(){
        method(new Fly(){
            @Override
            public void fly() {
                System.out.println("超人会飞");
            }
        });
        }
    public static void method(Fly fly) {
        fly.fly();
    }
    @Test
    public void test01(){
        new Father(){
            @Override
            public void show() {
                System.out.println("this is new Father show()");
            }
        }.show();
    }
    @Test
    public void test02(){
        Father father = new Father(99){
            @Override
            public void show() {
                System.out.println("this is new Father show-2()");
            }
        };
        father.show();
        father.test();
        System.out.println(father.num);
    }
}
class Father{
    int num;
    public Father(int num) {
        this.num = num;
    }

    public Father() {
    }

    public void test(){
        System.out.println("this is Father test");
    }

    public void show(){
        System.out.println("this is Father show()");
    }
}

·image-20220903012819536

匿名内部类练习一

image-20220903140738094

Employee.java

package com.sakura.innerclass.eaer;

public class Employee {
    private int num;
    private String name;
    private double salary;

    public Employee(int num, String name, double salary) {
        this.num = num;
        this.name = name;
        this.salary = salary;
    }

    public void setNum(int num) {
        this.num = num;
    }

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

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public int getNum() {
        return num;
    }

    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    @Override
    public String toString() {
        return "Employee{" +
                "num=" + num +
                ", name='" + name + '\'' +
                ", salary=" + salary +
                '}';
    }

    public Employee() {
    }
}

Test.java

package com.sakura.innerclass.eaer;

import java.util.Arrays;
import java.util.Comparator;

public class Test {
    public static void main(String[] args) {
        Employee e1 = new Employee(1,"李白",5489.21);
        Employee e2 = new Employee(2,"杜甫",6984.66);
        Employee e3 = new Employee(3,"白居易",8888.666);
        Employee e4 = new Employee(4,"苏轼",4569.44);
        Employee e5 = new Employee(5,"李清照",8999.99);
        Employee[] employees = {e1,e2,e3,e4,e5};
//        SortEmployee sortEmployee = new SortEmployee();
        System.out.println("排序前");
        arrayprint(employees);
        System.out.println("排序后");
        Arrays.sort(employees, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                Employee e1 = (Employee)o1;
                Employee e2 = (Employee)o2;
                return Double.compare(e1.getSalary(),e2.getSalary());
            }
        });
        arrayprint(employees);


    }
    public static void arrayprint(Employee[] e){
        for (Employee employee : e) {
            System.out.println(employee);
        }
    }
}

这里使用了匿名内部类,要重点关注

image-20220903153227023

运行结果:

image-20220903154308675

注解

image-20220903160756959

image-20220903161608984

项目:客户信息管理系统

需求

image-20220903162255657

image-20220903162314145

image-20220903162332627

开发简单架构

image-20220903162934336

day14

异常体系

image-20220906211332365

异常的演示

package com.sakura.exception;

import org.junit.Test;

public class test1 {
    @Test
    public void arryException(){
        int[] arr = {1,2,3};
        try {
            System.out.println(arr[3]);
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace(); //打印异常信息
            e.getMessage(); //获取异常位置
            System.out.println("该行代码已执行!");
        }

    }
}

image-20220906220355874

使用try catch处理异常

image-20220906224711456

image-20220906225236503

image-20220906225500468

但是这种写起来比较麻烦,如果采用了多层catch,我们可以省略为一个Exception

try{
    
}catch(xxx){
    
}catch(xxx){
    
}catch(Exception e){
}

使用try catch finally处理异常

image-20220906232454261

image-20220906234338231

使用throw和throws处理异常

image-20220907002856303

示例代码一:

package com.sakura.exception.throwexception;

public class ThrowException2 {
    public static void main(String[] args) {
        try{
            showMessage(4);
        }catch (ArrayIndexOutOfBoundsException e){
            System.err.println(e.getMessage());
            System.out.println("这行也执行啦");
        }
    }
    public static void showMessage(int index){
        int [] arr = {1,2,3};
        if(index <0 || index >= arr.length){
            throw new ArrayIndexOutOfBoundsException("数组下标越界了!");
        }
        System.out.println(arr[index]);
    }
}

此为运行时异常:

image-20220907010102445

示例代码二:

package com.sakura.exception.throwexception;

import java.io.File;
import java.io.FileNotFoundException;

public class ThrowException {
    public static void main(String[] args) {
        try {
            showMessage();
        } catch (FileNotFoundException e) {
            throw new RuntimeException(e);
        }
    }
    public static void showMessage() throws FileNotFoundException{
        File file = new File("C:\\Users\\Sakura\\Desktop\\图片\\love.jpg");
        boolean exists = file.exists();
        if(!exists){
            throw new FileNotFoundException("文件不存在o");
        }
        System.out.println(exists);
    }
}

这里是一个编译时异常,必须在方法名后throw异常

image-20220907004537390

异常类方法重写

image-20220910224705836

如,此时子类的异常比父类大就会报错,将异常换位置即可!

image-20220910225655631

自定义异常的方式

image-20220910231023392

day15

多线程简介

image-20220911001841326

image-20220911002102628

如何编写多线程程序?

  • 继承thread类
  • 实现Runnable接口
  • 实现Callable接口
  • 线程池

实现多线程方式一:继承Thread类

创建两条线程:

采用继承的方式创建多线程

  • 创建一个类继承Thead
  • 重写run方法,多线程会执行重写的方法
  • 启动线程:线程对象.start()
Thread.currentThead().getName()  # 获取当前线程名称

Test.java

package com.sakura.thread.extendthread;

public class Test1 {
    public static void main(String[] args) {
        Thread.currentThread().setName("这是线程一"); //设置主线程的名字
        RabbitThead rabbitThead = new RabbitThead(); //创建对象
        rabbitThead.setName("这是线程二"); //设置第二个线程名字
        rabbitThead.start(); //启动rabbitThead线程
        while (true){
            System.out.println(Thread.currentThread().getName()+"乌龟正在跑");
        }
    }
}

RabbitThread.java

package com.sakura.thread.extendthread;

public class RabbitThead extends Thread{
    public void run(){
        while (true){
            System.out.println(Thread.currentThread().getName()+"兔子正在跑");
        }
    }
}

运行结果:

image-20220911004936337

创建多线程方式二:实现Runnable接口

  • 创建一个对象实现 Runnable接口
  • 重写run方法
  • 创建 Runnable对象
  • 创建Thread对象 将 Runnable对象作为参数传递
  • 调用start()方法,启动线程

继承Thread类与实现Runnable接口创建多线程方法对比:

  • 继承的方式简单
  • 实现Runnable接口可以更好的实现资源共享

示例代码:

Test.java

package com.sakura.thread.runnablethread;

public class Test {

    public static void main(String[] args) {
        Thread.currentThread().setName("这是线程一");
        //1.创建Runnable对象
        RabbitRunnable rabbitRunnable = new RabbitRunnable();
        //2.创建Thead类,将 Runnable对象作为参数传递
        Thread t1 = new Thread(rabbitRunnable);
        t1.setName("这是线程二"); //设置线程二名字
        t1.start();        //开启线程
        while (true){
            System.out.println(Thread.currentThread().getName()+"乌龟跑");
        }
    }
}

RabbitRunnable.java

package com.sakura.thread.runnablethread;

public class RabbitRunnable implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println(Thread.currentThread().getName()+"兔子跑");
        }
    }
}

运行结果:

image-20220911012040254

采用匿名内部类的方式创建多线程程序

示例代码:

package com.sakura.thread;

import org.junit.Test;

public class AnonymousTest {
    public static void main(String[] args) {
        new Thread(){
            @Override
            public void run() {
                while (true){
                    System.out.println("乌龟跑");
                }
            }
        }.start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (true){
                    System.out.println("兔子跑");
                }
            }
        }).start();
    }
}

image-20220911113641398

使用构造器赋值线程名

一、继承Thread类构造器

使用继承的方式,可以采用this调用父类资源getName()

package com.sakura.thread;

public class Test1 {
    public static void main(String[] args) {
        RabbitThread1 t1 = new RabbitThread1("小白兔");
        RabbitThread1 t2 = new RabbitThread1("小灰兔");
        t1.start();
        t2.start();
    }
}
class RabbitThread1 extends Thread{
    public RabbitThread1(String name) {
        super(name);
    }
    @Override
    public void run() {
        for (int i = 0;i<5;i++){
            System.out.println(this.getName()+"正在跑");
        }
    }
}

image-20220912221159272

调用父类构造器

image-20220912221227523

二、继承Runnable接口

package com.sakura.thread;

public class Test2 {
    public static void main(String[] args) {
        ToriseThread toriseThread = new ToriseThread();
        Thread t1 = new Thread(toriseThread,"绿毛龟");
        Thread t2 = new Thread(toriseThread,"杰尼龟");
        t1.start();
        t2.start();
    }
}
class ToriseThread implements Runnable{
    @Override
    public void run() {
        for (int i = 0;i<5;i++){
            System.out.println(Thread.currentThread().getName()); //继承Runnable无法调用this
        }
    }
}

线程常用方法

构造方法:

image-20220912172319527

常用方法系列:

image-20220912172409403

构造器设置名字:

Test.java

package com.sakura.thread;

public class Test {
    public static void main(String[] args) {
        RabbitThread rabbitThread = new RabbitThread();
        Thread t1 = new Thread(rabbitThread,"小白兔");
        Thread t2 = new Thread(rabbitThread,"小黑兔");
        System.out.println("t1.isAlive()="+t1.isAlive());
        System.out.println("t2.isAlive()="+t2.isAlive());
        t1.start();
        t2.start();
        System.out.println("t1.isAlive()="+t1.isAlive());
        System.out.println("t2.isAlive()="+t2.isAlive());
    }
}
class RabbitThread implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println(Thread.currentThread().getName()+"正在跑");
        }
    }
}

设置优先级:

setPriority(优先级):
    1<= 优先级 <=10
// 如果没有指定,线程的默认优先级为5
// 优先级低也会执行,也有执行机会 

Test.java

package com.sakura.thread;

public class Test {
    public static void main(String[] args) {
        RabbitThread rabbitThread = new RabbitThread();
        Thread t1 = new Thread(rabbitThread,"小白兔");
        Thread t2 = new Thread(rabbitThread,"小黑兔");
        t1.setPriority(10);
        t2.setPriority(1);
        t1.start();
        t2.start();
    }
}
class RabbitThread implements Runnable{
    @Override
    public void run() {
        for(int i =0;i<20;i++){
            System.out.println(Thread.currentThread().getName()+"正在跑");
        }
    }
}

输出结果:

小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小黑兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小白兔正在跑
小黑兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小白兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑
小黑兔正在跑

设置睡眠:

Test.java

package com.sakura.thread;

public class Test {
    public static void main(String[] args) {
        RabbitThread rabbitThread = new RabbitThread();
        Thread t1 = new Thread(rabbitThread,"小白兔");
        Thread t2 = new Thread(rabbitThread,"小黑兔");
        t1.setPriority(10);
        t2.setPriority(1);
        t1.start();
        t2.start();
    }
}
class RabbitThread implements Runnable{
    @Override
    public void run() {
        for(int i =0;i<100;i++){
            //run方法出现异常只能采用 try{}catch{}方式处理 因为子类不能抛出比父类更大的异常
            //而Runnable中没有抛出异常
            try {
                Thread.sleep(1000); //单位是毫秒
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+"正在跑");
        }
    }
}

使用join方法插队:

插队的线程调用join(2000)那么被插队的线程要进行等待 2000ms等插队的线程执行完毕后或者等待时间已到那么继续执行

package com.sakura.thread;

public class Test {
    public static void main(String[] args) {
        RabbitThread rabbitThread = new RabbitThread();
        Thread t1 = new Thread(rabbitThread,"小白兔");
        t1.start();
        for(int i=0;i<20;i++){
            if (i==10){
                try {
                    t1.join();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("主线程跑\t"+i);
        }
    }
}
class RabbitThread implements Runnable{
    @Override
    public void run() {
        for(int i =0;i<20;i++){
            System.out.println(Thread.currentThread().getName()+"\t正在跑\t"+i);
        }
    }
}

输出:

主线程跑    0
主线程跑    1
主线程跑    2
主线程跑    3
主线程跑    4
主线程跑    5
主线程跑    6
主线程跑    7
主线程跑    8
小白兔    正在跑    0
主线程跑    9
小白兔    正在跑    1
小白兔    正在跑    2
小白兔    正在跑    3
小白兔    正在跑    4
小白兔    正在跑    5
小白兔    正在跑    6
小白兔    正在跑    7
小白兔    正在跑    8
小白兔    正在跑    9
小白兔    正在跑    10
小白兔    正在跑    11
小白兔    正在跑    12
小白兔    正在跑    13
小白兔    正在跑    14
小白兔    正在跑    15
小白兔    正在跑    16
小白兔    正在跑    17
小白兔    正在跑    18
小白兔    正在跑    19
主线程跑    10
主线程跑    11
主线程跑    12
主线程跑    13
主线程跑    14
主线程跑    15
主线程跑    16
主线程跑    17
主线程跑    18
主线程跑    19

如果我们设置下等待时间:

package com.sakura.thread;

public class Test {
    public static void main(String[] args) {
        RabbitThread rabbitThread = new RabbitThread();
        Thread t1 = new Thread(rabbitThread,"小白兔");
        t1.start();
        for(int i=0;i<20;i++){
            if (i==10){
                try {
                    t1.join(2000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println("主线程跑\t"+i);
        }
    }
}
class RabbitThread implements Runnable{
    @Override
    public void run() {
        for(int i =0;i<20;i++){
            try {
                Thread.sleep(4000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            System.out.println(Thread.currentThread().getName()+"\t正在跑\t"+i);
        }
    }
}

此时输出结果:

主线程跑    0
主线程跑    1
主线程跑    2
主线程跑    3
主线程跑    4
主线程跑    5
主线程跑    6
主线程跑    7
主线程跑    8
主线程跑    9
主线程跑    10
主线程跑    11
主线程跑    12
主线程跑    13
主线程跑    14
主线程跑    15
主线程跑    16
主线程跑    17
主线程跑    18
主线程跑    19
小白兔    正在跑    0
小白兔    正在跑    1
    ...

常用方法系列二

image-20220912224414761

image-20220912225128380

yield()方法-线程的礼让

所谓线程的礼让不过是从运行状态先回到就绪状态,事实上,当优先级相同时,它们仍然具有相同的概率被调用!

示例代码:

package com.sakura.thread.method;

public class Test {
    public static void main(String[] args) {
        RabbitThread rabbitThread = new RabbitThread();
        Thread t1 = new Thread(rabbitThread,"小灰兔");
        t1.start();
        for (int i =0; i<20;i++){
            if (i==5){
                Thread.yield();
            }
            System.out.println(Thread.currentThread().getName()+"\t正在运行\t"+i);
        }
    }
}
class RabbitThread implements Runnable{
    @Override
    public void run() {
        for(int i = 0; i<20; i++){
            System.out.println(Thread.currentThread().getName()+"\t正在运行\t"+i);
        }
    }
}

stop()与setDaemon(true)

stop() //结束线程
setDaemon(true) //守护线程        

setDaemon的示例用法:

package com.sakura.thread.method;

public class Test {
    public static void main(String[] args) {
        RabbitThread rabbitThread = new RabbitThread();
        Thread t1 = new Thread(rabbitThread,"小灰兔");
        t1.setDaemon(true);
        t1.start();
        for (int i =0; i<30;i++){
            System.out.println(Thread.currentThread().getName()+"\t正在运行\t"+i);
        }
    }
}
class RabbitThread implements Runnable{
    @Override
    public void run() {
        while (true){
            System.out.println(Thread.currentThread().getName()+"\t正在运行\t");
        }
    }
}

t1进程是主进程的守护进程,当主进程停止时,t1也会随之停止

image-20220912233804696

volatile

volatile的作用是确保不会因编译器的优化而省略某些指令,volatile的变量是说这变量可能会被意想不到地改变,每次都小心地重新读取这个变量的值,而不是使用保存在寄存器里的备份,这样,编译器就不会去假设这个变量的值了。

image-20220913001220149

示例代码:

package com.sakura.thread.method;

public class Test {
    public volatile static boolean flag = true; //当没有加volatile程序不会结束,加上后才会结束
    public static void main(String[] args) {
        new Thread(new Runnable() {
            @Override
            public void run() {
                while (flag){
//                    System.out.println("程序执行中~~~");
                }
            }
        }).start();
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        flag = false;

    }
}

线程安全

image-20220913002500973

线程安全问题:当多个线程操作共享数据时有可能会发生线程安全问题
解决线程安全问题:
同步代码块
同步方法
Lock : 公平锁 非公平锁 juc

模拟火车站卖票,体现线程安全问题:

问题代码:

package com.sakura.thread.ticket;

public class Test {
    public static void main(String[] args) {
        TicketThread ticketThread1 = new TicketThread("售票点一");
        TicketThread ticketThread2 = new TicketThread("售票点二");
        TicketThread ticketThread3 = new TicketThread("售票点三");
        ticketThread1.start();
        ticketThread2.start();
        ticketThread3.start();
    }

}

class TicketThread extends Thread{
    public TicketThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        int count = 100;
        while (true){
            if (count <= 0){
                break;
            }
            System.out.println(Thread.currentThread().getName()+"已卖出第"+count+"票!");
            count--;
        }
    }
}

image-20220913004908511

我们可以发现卖的票有重复的,我们本想要卖100张,因为多线程我们实际卖了300张。

使用同步代码块解决线程安全问题

出现的问题出现了0票或者重复的票,需要有一个监视器查看卖票的数据

解决方式一:使用同步代码块:

synchronized(同步监视器对象){

} //同步监视器对象必须是引用数据类型,当多条线程操作共享数据同步监视器对象必须是同一个

image-20220913011504347

保证在同步代码块内只有一条线程在执行其他线程需要在同步代码块外等待

package com.sakura.thread.ticket;

public class Test {
    public static void main(String[] args) {
        TicketThread ticketThread1 = new TicketThread("售票点一");
        TicketThread ticketThread2 = new TicketThread("售票点二");
        TicketThread ticketThread3 = new TicketThread("售票点三");
        ticketThread1.start();
        ticketThread2.start();
        ticketThread3.start();
    }
}
class TicketThread extends Thread{
    static int count = 100;
    public TicketThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        while (true) {
            synchronized (TicketThread.class) {
                if (count <= 0) {
                    break;
                }
                System.out.println(this.getName() + "已卖出第" + count + "票!");
                count--;
            }
        }
        }
    }

输出结果:

image-20220913012215185

ps:当一条线程进入同步代码块内,那么其他线程不能进入拥有同一个同步监视器对象的同步代码块

image-20220913233014600

使用同步方法解决线程安全问题

有一条线程进入同步方法那么其他线程不仅不能进入此方法也不能进入拥有同一个同步监视器对象的同步方法

示例代码:

package com.sakura.thread.ticket;

public class Test {
    public static void main(String[] args) {
        TicketThread ticketThread = new TicketThread();
        Thread t1 = new Thread(ticketThread,"售票点一");
        Thread t2 = new Thread(ticketThread,"售票点二");
        Thread t3 = new Thread(ticketThread,"售票点三");
        t1.start();
        t2.start();
        t3.start();
        t2.setPriority(10);
        t1.setPriority(1);
    }
}
class TicketThread implements Runnable{
    int count = 100;
    @Override
    public void run() {
        while (true){
            if (count <=0){
                return;
            }
            saleTicket();
        }

    }
    private synchronized void saleTicket(){
        if (count <=0){
            return;
        }
        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(Thread.currentThread().getName()+"第"+count+"票已卖出");
        count--;
    }
}

image-20220914002516038

使用同步代码块解决线程安全问题-练习题

image-20220914010445756

package com.sakura.thread;

import java.util.Scanner;

public class AccountTest {
    public static void main(String[] args) {
        AccountRunnable account = new AccountRunnable();
        Thread t1 = new Thread(account,"HJY");
        Thread t2 = new Thread(account,"WYF");
        t1.start();
        t2.start();
    }
}
class Account{
    int balance = 600;
    public void withMoney(int money){
        balance -= money;
    }
}
class AccountRunnable implements Runnable{
    Account account = new Account();
    @Override
    public void run() {
            synchronized (account){
                if (account.balance < 500){
                    System.out.println(Thread.currentThread().getName()+"\t您的余额不足,取款失败\t"+account
                            .balance);
                }else {
                    account.withMoney(500);
                    System.out.println(Thread.currentThread().getName()+"\t恭喜您\t"+"已成功取出500元"+"您的余额为"+account.balance);
        }
    }
}}

image-20220914010500892

单例模式

image-20220914233953966

饿汉式:

示例代码:

package com.sakura.thread.single;

public class Test {
    public static void main(String[] args) {
        Single s1 = Single.INSTANCE;
        Single s2 = Single.INSTANCE;
        System.out.println(s1==s2);
        Single1 s3 = Single1.INSTANCE;
        Single1 s4 = Single1.INSTANCE;
        System.out.println(s3==s4);
    }
}
class Single{
    public static final Single INSTANCE = new Single(); //提前将对象创建了出来
    private Single() {
    }
}
enum Single1 {
    INSTANCE
}

懒汉式:

package com.sakura.thread.single;

public class Test {
    public static void main(String[] args) {
        LazyGuys s1 = LazyGuys.withsingle();
        LazyGuys s2 = LazyGuys.withsingle();
        System.out.println(s1==s2);
    }
}
class LazyGuys{
    private LazyGuys(){}
    private static LazyGuys lazyGuys;
    public synchronized static LazyGuys withsingle(){
        if (lazyGuys == null){
            synchronized (Test.class){
            LazyGuys lazyGuys = new LazyGuys();
        }
        }
        return lazyGuys;
    }
}

image-20220915002527942

day16

线程通信的初识

多个线程在处理同一个资源,但是处理的动作(线程的任务)却不相同。而多个线程并发执行时,在默认情况下CPU是随机切换线程的,当我们需要多个线程来共同完成一件任务,并且我们希望他们有规律的执行,那么多线程之间需要一些通信机制,可以协调它们的工作,以此来帮我们达到多线程共同操作一份数据。
比如:线程A用来生成包子的,线程B用来吃包子的,包子可以理解为同一资源,线程A与线程B处理的动作,一个是生产,一个是消费,此时B线程必须等到A线程完成后才能执行,那么线程A与线程B之间就需要线程通信,即等待唤醒机制

image-20220915003001047

image-20220915003444873

线程通信采用同步代码实现

image-20220915003737856

示例代码:

package com.sakura.thread.notify;

public class Test {
    public static void main(String[] args) {
        Bar bar = new Bar();
        CookerThread c1 = new CookerThread(bar);
        WaiterThread w1 = new WaiterThread();
        w1.setBar(bar);
        c1.setName("五星级大厨");
        w1.setName("海底捞服务员");
        c1.start();
        w1.start();
    }
}
class Bar{
    int count = 0;
    public static final int MAX_ENUM = 10;
}
class CookerThread extends Thread{
    Bar bar;
    public CookerThread(Bar bar) {
        this.bar = bar;
    }
    @Override
    public void run() {
        while (true) {
            synchronized (bar) {
                if (bar.count >= bar.MAX_ENUM) {
                    try {
                        bar.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                bar.count++;
                System.out.println(Thread.currentThread().getName() + "正在做菜中,这是第" + bar.count + "份菜");
                bar.notify();
            }
        }
    }
}
class WaiterThread extends Thread{
    private Bar bar;

    public void setBar(Bar bar) {
        this.bar = bar;
    }

    @Override
    public void run() {
        while (true) {
            synchronized (bar) {
                if (bar.count <= 0) {
                    try {
                        bar.wait();
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                bar.count--;
                System.out.println(Thread.currentThread().getName() + "正在端菜中,端走后还有" + bar.count + "份菜");
                bar.notify();
            }
        }
        }
    }

死锁

image-20220915134622203

产生死锁的原因两条线程互相持有对方的锁资源不放松,可以让一条线程先跑完另一条线程再开始

示例代码:

package com.sakura.thread.deadlock;

public class Test {
    public static void main(String[] args) {
        Object goods = new Object();
        Object money = new Object();
        CustomerThread customerThread = new CustomerThread(goods, money);
        GoodsThread goodsThread = new GoodsThread(goods, money);
        customerThread.setName("供应商");
        goodsThread.setName("采购商");
        customerThread.start();
        goodsThread.start();
    }
}
    class CustomerThread extends Thread{
        Object goods;
        Object money;

        public CustomerThread(Object goods, Object money) {
            this.goods = goods;
            this.money = money;
        }

        @Override
        public void run() {
            synchronized (goods){
                System.out.println(Thread.currentThread().getName()+":你奶奶滴,先发货再给钱");
                synchronized (money){
                    System.out.println(Thread.currentThread().getName()+":已付钱");
                }
            }
        }
    }
    class GoodsThread extends Thread{
        Object goods;
        Object money;
        public GoodsThread(Object goods, Object money) {
            this.goods = goods;
            this.money = money;
        }
        @Override
        public void run() {
            synchronized (money){
                System.out.println(Thread.currentThread().getName()+":你奶奶滴,先给钱再发货");
                synchronized (goods){
                    System.out.println(Thread.currentThread().getName()+":已发货");
                }
            }

        }

    }

此时便形成了死锁

image-20220915142520962

如何解决?

image-20220915142811474

在两个启动线程的代码中间,使主线程睡眠一段时间,即可避免

image-20220915142903030

线程的生命周期

观点一

image-20220915145205272

观点二

image-20220915145534600

基础api与常见算法

image-20220915145954683

和数学相关的类

java.lang.Math

image-20220915150308868

abs: 求绝对值
ceil: 向上取整
floor: 向下取整
random(): 随机数 [0,1) 左闭右开
n 较大的数 m 较小的数
[m,n]  ---->       (int)(Math.random()*(n-m+1)+m);
pow(n,y)   : n^y
sqrt() :开平方
round(): 四舍五入

示例代码:

package com.sakura.api;

public class MathTest {
    public static void main(String[] args) {
        System.out.println(Math.abs(-10));
        System.out.println(Math.ceil(3.00001));
        System.out.println(Math.floor(1.999999));
        System.out.println(Math.random());
        int n = 100;
        int m = 55;
        System.out.println((int)(Math.random()*(n-m+1)));
        System.out.println(Math.pow(2, 4));
        System.out.println(Math.sqrt(64));
        System.out.println(Math.round(5.4999));
        System.out.println(Math.round(5.5));
    }
}

image-20220915152440508

BigInteger类

存储大的整数

示例代码:

package com.sakura.api;

import java.math.BigInteger;

public class Test1 {
    public static void main(String[] args) {
        BigInteger bigInteger = new BigInteger("999999999998484844554544545");
        System.out.println(bigInteger);
        BigInteger b1 = new BigInteger("300");
        BigInteger b2 = new BigInteger("200");
        System.out.println("加法\tb1.add(b2) = " + b1.add(b2));
        System.out.println("减法\tb1.subtract(b2) = " + b1.subtract(b2));
        System.out.println("乘法\tb1.multiply(b2) = " + b1.multiply(b2));
        System.out.println("除法\tb1.divide(b2) = " + b1.divide(b2));
        System.out.println("余数\tb1.remainder(b2) = " + b1.remainder(b2));
    }
}

image-20220915161917396

BigDecimal类

存储确切的小数

package com.sakura.api;

import java.math.BigDecimal;
import java.math.BigInteger;

public class Test1 {
    public static void main(String[] args) {
        BigDecimal bigDecimal = new BigDecimal("3.1415926");
        System.out.println(bigDecimal);
        BigDecimal b1 = new BigDecimal("10.00");
        BigDecimal b2 = new BigDecimal("3.00");
        System.out.println("加法\tb1.add(b2) = " + b1.add(b2));
        System.out.println("减法\tb1.subtract(b2) = " + b1.subtract(b2));
        System.out.println("乘法\tb1.multiply(b2) = " + b1.multiply(b2));
        System.out.println("除法\tb1.divide(b2) = " + b1.divide(b2,20,BigDecimal.ROUND_FLOOR));
        System.out.println("余数\tb1.remainder(b2) = " + b1.remainder(b2));

    }
}

image-20220915162943916

Random类

image-20220915212254933

import java.util.Random;

public class Test1 {
    public static void main(String[] args) {
        Random random = new Random();
        for (int i =0; i<5;i++){
            System.out.print(random.nextInt(50)+"\t");
            System.out.print(random.nextBoolean()+"\t");
            System.out.print(random.nextDouble()+"\t");
            System.out.println();
        }
    }
}

image-20220915212834940

还可以设置种子:

import java.util.Random;

public class Test1 {
    public static void main(String[] args) {
        Random random = new Random(1);  //此处设置种子为1
        for (int i =0; i<10;i++){
            System.out.println(random.nextInt(50)+"\t");
        }
    }
}

输出:

35    
38    
47    
13    
4    
4    
34    
6    
28    
48    

每次运行程序,输出的结果都一致

日期时间Api

已经过时的方法:

image-20220915221033738

Calendar类

image-20220915222848061

image-20220915223307597

示例代码:

package com.sakura.api;

import java.util.Calendar;

public class Test1 {
    public static void main(String[] args) {
        Calendar calendar = Calendar.getInstance();
        //System.out.println(calendar);
        System.out.println("calendar.get(Calendar.YEAR) = " + calendar.get(Calendar.YEAR));
        System.out.println("(calendar.get(Calendar.MONTH)+1) = " + (calendar.get(Calendar.MONTH) + 1));
        System.out.println("calendar.get(Calendar.DATE) = " + calendar.get(Calendar.DATE));
        System.out.println("calendar.get((Calendar.HOUR)) = " + calendar.get((Calendar.HOUR)));
        /*修改日期
        *属性: year,month,data...
        * 值:正数 向后 负数 向前
        * calender(属性,值);
        * */
        calendar.add(Calendar.YEAR,28);
        System.out.println("calendar.get(Calendar.YEAR) = " + calendar.get(Calendar.YEAR));
        calendar.add(Calendar.YEAR,20);
        System.out.println("calendar.get(Calendar.YEAR) = " + calendar.get(Calendar.YEAR));
        /*
        设置时间
        calender.set(year,month,data)
         */
        calendar.set(2050,1,1,5,20);
        System.out.println("calendar.get(Calendar.YEAR) = " + calendar.get(Calendar.YEAR));
        System.out.println("calendar.get(Calendar.MONTH) = " + calendar.get(Calendar.MONTH));
    }
}

输出:

calendar.get(Calendar.YEAR) = 2022
(calendar.get(Calendar.MONTH)+1) = 9
calendar.get(Calendar.DATE) = 15
calendar.get((Calendar.HOUR)) = 11
calendar.get(Calendar.YEAR) = 2050
calendar.get(Calendar.YEAR) = 2070
calendar.get(Calendar.YEAR) = 2050
calendar.get(Calendar.MONTH) = 1

获取时区

import java.util.TimeZone;

public class Test1 {
    public static void main(String[] args) {
        String[] availableIDs = TimeZone.getAvailableIDs();
        for(String availableID : availableIDs){
            System.out.println(availableID);
        }
    }
}

image-20220915232253904

日期格式化

image-20220916000801519

示例代码:

import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DataTest {
    public static void main(String[] args) throws ParseException {
            /*
    日期转换:
     */
        //    日期-->字符串
        DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date1 = new Date();
        System.out.println(date1);
        String res1 = df1.format(date1);
        System.out.println(res1);
        //    字符串-->日期
        DateFormat df2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String datastr = "2022-09-16 00:15:41"; //要解析的字符串内容必须与格式完全匹配,否则报错
        Date date2 = df2.parse(datastr);
        System.out.println(date2);
    }
}

新增的三个日期对象

image-20220916002810246

示例代码:

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.Month;

public class TestDate {
    public static void main(String[] args) {
        /*
        LocalDate 年 月 日
        不可变日期,一旦对日期做出修改会生成一个新的LocalDate记录改变后的日期
        minusDays():日期减少
         */
        //对 年 月 日 进行操作
        LocalDate now = LocalDate.now();
        System.out.println(now);
        int year = now.getYear();
        int month = now.getMonthValue();
        int day = now .getDayOfMonth();
        System.out.println("year = " + year);
        System.out.println("month = " + month);
        System.out.println("day = " + day);

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

        Month month1 = now.getMonth();
        System.out.println("month1 = " + month1);
        System.out.println(month1.getValue());

        System.out.println("-----------");
        
        LocalDate localDate = now.minusDays(15);
        System.out.println("now = " + now);
        System.out.println("localDate = " + localDate);

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

        LocalDate of = LocalDate.of(2050,12,31); //对年月日进行操作
        System.out.println(of);
        LocalDate localDate1 = of.plusDays(1);
        System.out.println(localDate1);

        System.out.println("-----------");
        //对 时 分 秒 进行操作
        LocalTime localTime = LocalTime.now();
        System.out.println("localTime = " + localTime);//尾数是纳秒

        System.out.println("-----------");
        //同时对 年 月 日 时 分 秒 进行操作
        LocalDateTime  localDateTime = LocalDateTime.now();
        System.out.println("localDateTime = " + localDateTime);
        LocalDateTime of1 = LocalDateTime.of(2050,12,31,15,22);
        System.out.println("of1 = " + of1);
    }
}

输出:

2022-09-16
year = 2022
month = 9
day = 16
-----------
month1 = SEPTEMBER
9
-----------
now = 2022-09-16
localDate = 2022-09-01
-----------
2050-12-31
2051-01-01
-----------
localTime = 01:13:08.425
-----------
localDateTime = 2022-09-16T01:13:08.425
of1 = 2050-12-31T15:22

获取与指定时区时间和两个日期间隔

image-20220916140917835

使用period计算时间间隔

示例代码:

import java.time.LocalDate;
import java.time.Period;

public class Test2 {
    public static void main(String[] args) {
        LocalDate l1 = LocalDate.now();
        LocalDate l2 = LocalDate.of(2050,2,18);
        System.out.println("l1 = " + l1);
        System.out.println("l2 = " + l2);
        Period period = Period.between(l1,l2);
        System.out.println("period = " + period);
        System.out.println("period.getYears() = " + period.getYears());
        System.out.println("period.getMonths() = " + period.getMonths());
    }
}

image-20220916142343404

使用Duration计算两个时间间隔

示例代码:

import java.time.Duration;
import java.time.LocalDateTime;

public class Test2 {
    public static void main(String[] args) {
        LocalDateTime l1 = LocalDateTime.now();
        LocalDateTime l2 = LocalDateTime.of(2050,12,31,15,21);
        Duration duration = Duration.between(l1,l2); //计算两个时间的时间间隔
        System.out.println("duration = " + duration);
        System.out.println("duration.toDays() = " + duration.toDays());
        System.out.println("duration.toHours() = " + duration.toHours());
    }
}

image-20220916142900289

DateTimeFormatter类:日期格式化类

示例代码:

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

public class Test2 {
    public static void main(String[] args) {
        LocalDateTime l1 = LocalDateTime.now();
        System.out.println("l1 = " + l1);
        /*
        将日期转为字符串
         */
        DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE; // DateTimeFormatter 有提供好的模板,可以直接使用
        String format = formatter.format(l1);
        System.out.println("format = " + format);
        //自定义格式
        DateTimeFormatter formatter1 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss E");
        String result = formatter1.format(l1);
        System.out.println("result = " + result);
        /*
        将字符串转化为日期
         */
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss E");
        String str = "2022-09-16 14:51:26 星期五";
        LocalDateTime parse= LocalDateTime.parse(str,formatter2);
        System.out.println("parse = " + parse);
    }
}

image-20220916150014010

系统相关类

image-20220916151720605

import java.util.Properties;

public class SystemTest {
    public static void main(String[] args) {
        long l = System.currentTimeMillis(); //
        System.out.println("l = " + l);
        System.gc(); //运行垃圾回收器
        int [] arr = {10,20,30};
        int [] newArr = new int[arr.length];
        System.arraycopy(arr,0,newArr,0,arr.length);
        for (int i :newArr){
            System.out.println(i);
        }
        System.out.println("-----------------");
        Properties properties = System.getProperties();
//        properties.list(System.out);
        String property = System.getProperty("java.version");
        System.out.println("property = " + property);
        // Runtime
        Runtime r1 = Runtime.getRuntime();
        Runtime r2 = Runtime.getRuntime();
        System.out.println(r1==r2); //说明了Runtime创建的对象都是同一个
        System.out.println("r1.totalMemory() = " + r1.totalMemory()); //总内存
        System.out.println("r1.freeMemory() = " + r1.freeMemory()); //剩余内存
    }
}

image-20220916170328632

数组的算法升华

数组的反转

image-20220918230400278

方法一 创建一个新数组

public class ArrayTest {
    public static void main(String[] args) {
        int [] arr = {10,20,30,40,50,60,70};
        //交换方法一 创建一个新数组
        int [] newarr = new int[arr.length];
        int index = 0;
        for (int i =arr.length-1;i>=0;i--){
            newarr[index++] = arr[i];
        }
        for (int i : newarr) {
            System.out.println(i);
        }
    }
}

image-20220918233551604

方法二数组内交换

public class ArrayTest {
    public static void main(String[] args) {
        int [] arr = {10,20,30,40,50,60,70};
        //交换方法二 数组内交换
        for (int i =0;i<arr.length/2;i++){
            int temp;
            temp = arr[i];
            arr[i] = arr[arr.length-1-i];
            arr[arr.length-1-i] = temp;
        }
        for (int i : arr) {
            System.out.println(i);
        }
    }
}

image-20220918234451781

数组的二分查找

public class ArrayTest {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30, 40, 50, 60, 70,82,92,103};
        //二分查找。二分查找排序必须是有序的
        int res = binarySearch(arr,103);
        System.out.println("您要查找的数字下标为"+res);
    }
    private static int binarySearch(int[] arr, int ele) {
        int ArrIndex = 0;
        int ArrEnd = arr.length - 1;
        while (ArrIndex <= ArrEnd) {
            int ArrMid = (ArrIndex + ArrEnd) / 2;
            if (ele > arr[ArrMid]) {
                ArrIndex = ArrMid + 1;
            } else if (ele < arr[ArrEnd]){
                ArrEnd = ArrMid;
            } else {
                return ArrMid;
            }
        }
        return -1;
    }
}

image-20220919002943734

day17

数组的扩容

示例代码:

public class ArrTest {
    @Test
    public void test01(){
        //旧数组不够要扩容
        String [] strarr = {"张三","李四","王五"};
        //现在有需求,需要将数组扩容至原来的两倍、
        String [] newarr = new String[strarr.length*2];
        //先将旧数组复制到新数组
        System.arraycopy(strarr,0,newarr,0,3);
        //添加需要的值
        newarr[strarr.length] = "李白";
        newarr[strarr.length+1] = "杜甫";
        newarr[strarr.length+2] = "白居易";
        //将新数组的地址赋值给旧数组
        strarr = newarr;
        //输出旧数组
        for (String s : strarr) {
            System.out.println(s);
        }
    }
}

image-20220921144123079

数组的插入

数组未满

示例代码:

     @Test
    public void test02(){
        //数组的插入,分两种情况,数组未满和数组已满
        //1.数组未满
        String [] arr = new String[5];
        arr[0] = "蔡徐坤";
        arr[1] = "肖战";
        arr[2] = "王一博";
        System.arraycopy(arr,1,arr,2,2); //从第二个元素开始,整体后移一个位置
        arr[1] = "赵四"; //在第二个位置插入赵四
        for (String s : arr) {
            System.out.println(s);
        }
    }

image-20220921150522702

数组已满

示例代码:

    @Test
    public void test03(){
        //数组已满的时候插入元素
        String [] arr = {"张三","李四","王五"};
        //需求:在张三和李四中间插入一个蔡徐坤
        //由于数组已满,所以我们需要进行扩容,并将改变之前的赋值给新数组
        String [] newarr = new String[arr.length+1]; //扩容操作
        int index = 1;
        for (int i =0;i<index;i++){
            newarr[i] = arr[i];
        }
        System.arraycopy(arr,1,newarr,2,2);
        newarr[1] = "蔡徐坤";
        arr = newarr;
        for (String s : arr) {
            System.out.println(s);
        }
    }

image-20220921151843085

数组的删除

image-20220921160641109

思路一:

新建一个数组

    @Test
    public void test04(){
        String [] arr = {"张三","李四","王五"};
        //新建一个数组
        String [] newarr = new String[arr.length-1];
        newarr[0] = arr[0];
        newarr[1] = arr[2];
        arr = newarr;
        for (String s : arr) {
            System.out.println(s);
        }
    }

image-20220921161127117

思路二:

在数组内进行操作

    @Test
    public void test05(){
        String [] arr = {"张三","李四","王五"};
        //数组内进行操作
        System.arraycopy(arr,2,arr,1,1);
        arr[2] = null;
        for (String s : arr) {
            System.out.println(s);
        }

    }

image-20220921161356596

选择排序

image-20220921165230529

示例代码:

    @Test
    public void test06(){
        int [] arr = {100,50,90,45,56,73,20};
        for (int i =0;i<arr.length-1;i++){
            int minindex = i;
            for (int j=i+1;j<=arr.length-1;j++){
                if (arr[minindex] <= arr[j]){
                    continue;
                }else {
                    minindex = j;
                }
            }
            int temp = arr[i];
            arr[i] = arr[minindex];
            arr[minindex] = temp;
        }
        for (int i : arr) {
            System.out.println(i);
        }
    }

image-20220921172432856

数组的工具类

Arrays.toString函数

    @Test
    public void test11(){
        int [] arr = {10,20,50,32,12};
        System.out.println(arr);
        System.out.println(Arrays.toString(arr));
    }

image-20220922140706344

输出数组的值

Arrays.deepToString函数

Array.toString函数只能显示一维数组

    @Test
    public void test11(){
        int [] [] arrs = {{1,2},{22,43},{97,67}};
        System.out.println(Arrays.toString(arrs));
        System.out.println(Arrays.deepToString(arrs));
    }

image-20220922141005991

Arrays.sort方法

    @Test
    public void test07(){
        //Array.sort可以对数组进行排序
        int [] arr = {50,56,12,80,5};
        System.out.println(Arrays.toString(arr));
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));
    }

image-20220922133838302

问题:如何对对象数组进行比较?

如果我们直接进行排序就会报错,因为程序不知道根据什么进行比较

image-20220922134730091

image-20220922134744471

解决方法:重写Comparable

方法一:继承的方式

示例代码:

    public void test08(){
        Person p1 = new Person("David",17);
        Person p2 = new Person("瑞贝卡",15);
        Person p3 = new Person("Lucy",19);
        Person [] arr = {p1,p2,p3};
        System.out.println(Arrays.toString(arr));
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));

    }
    class Person implements Comparable{
        @Override
        public int compareTo(Object o) {
            Person p = (Person)o;
            return this.age-p.age;
        }

        String name;
        int age;

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

        public String getName() {
            return name;
        }

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

        public int getAge() {
            return age;
        }

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

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

image-20220922135320269

方法二:采用匿名内部类

    @Test
    public void test09(){
        Person p1 = new Person("David",17);
        Person p2 = new Person("瑞贝卡",15);
        Person p3 = new Person("Lucy",19);
        Person [] arr = {p1,p2,p3};
        System.out.println(Arrays.toString(arr));
        Arrays.sort(arr, new Comparator<Person>() {
            @Override
            public int compare(Person o1, Person o2) {
                Person p1 = (Person) o1;
                Person p2 = (Person) o2;
                return p1.getAge()-p2.getAge();
            }
        });
        System.out.println(Arrays.toString(arr));
    }
    class Person{
        String name;
        int age;

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

        public String getName() {
            return name;
        }

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

        public int getAge() {
            return age;
        }

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

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

image-20220922135738345

Arrays.fill函数

注意:此函数范围为左闭右开

[n,m)

    @Test
    public void test10(){
        int [] arr = {10,20,50,32,12};
        System.out.println(Arrays.toString(arr));
        Arrays.fill(arr,0,2,666); //注意:此函数范围是左闭右开
        System.out.println(Arrays.toString(arr));
    }

image-20220922140159868

Arrays.equals函数

比较的是内容及其下标是否完全一致

    @Test
    public void test12(){
        int [] arr1 = {10,20,50,32,12};
        int [] arr2 = {10,20,50,32,12};
        System.out.println(arr1==arr2);
        boolean flag = Arrays.equals(arr1,arr2);
        System.out.println("flag = " + flag);
    }

image-20220922141245975

Arrays.copyOf函数

复制旧数组,创建一个新数组

    @Test
    public void test13(){
        int [] arr1 = {10,20,50,32,12};
        int [] arr2 = Arrays.copyOf(arr1,2);
        System.out.println(Arrays.toString(arr2));
    }

image-20220922141529755

Arrays.copyOfRange函数

复制旧数组的一段,创建一个新数组

范围也是左闭右开

[n,m)

    @Test
    public void test13(){
        int [] arr1 = {10,20,50,32,12};
        int [] arr2 = Arrays.copyOfRange(arr1,2,4);
        System.out.println(Arrays.toString(arr2));
    }

image-20220922141939165

字符串的简介介绍

image-20220922143602790

创建字符串的方式

public class TestSrting {
    public static void main(String[] args) {
        //方式一
        String s1 = "你好";
        //方式二
        char [] a = {'a','b'};
        String s2 = new String(a);
        System.out.println(s2);
        //方式三
        String s3 = new String("世界");
        //方式四
        byte [] bytes = {65,66,67,97};
        String s4 = new String(bytes); //会将byte类型中的数字解析为对应字符
        System.out.println(s4);
        String s5 = new String(bytes,1,2); //从1开始,取两个
        System.out.println(s5);
        //方式五 通过方法创建
        char [] c = {'a','b','c'};
        int b = 5;
        String s6 = ""+b; //字符串与整数相连接成为字符串
        String s7 = String.valueOf(b); //方法返回值为字符串
        String s8 = String.copyValueOf(c,0,3);
        //方法有很多,多翻阅文档
    }
}

对象的个数问题

public class TestSrting {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1==s2);
        System.out.println(s1.equals(s2));
        
    }
}

image-20220922150958579

image-20220922151425322

public class TestSrting {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = new String("hello");
        System.out.println(s1==s2);
        System.out.println(s1.equals(s2));
    }
}

image-20220922151244855

image-20220922151514096

String内存分析

image-20220922153204909

image-20220922153526437

字符串的拼接

image-20220922172731643

image-20220922172901733

image-20220922173113725

jdk7以后,调用intern方法时,如果该字符串已经存在于常量池中,则将常量池中的引用直接返回;如果不存在,则在常量池中生成一个对原字符串的引用。

image-20220922173746272

字符串常用方法一

image-20220922212123884

字符串常用方法二

public class TestSrting {
    public static void main(String[] args) {
        String message = "hello word!";
        //contain 判断是否包含指定字符串
        boolean flag1 = message.contains("he");
        boolean flag2 = message.contains("he11");
        System.out.println("flag1 = " + flag1);
        System.out.println("flag2 = " + flag2);
        //indexOf 查找指定元素第一次出现得下标,从0开始 不存在返回-1
        int res1 = message.indexOf("l");
        int res2 = message.indexOf("o");
        System.out.println("res1 = " + res1);
        System.out.println("res2 = " + res2);
        //lastIndexOf 查找指定元素最后一次出现的位置 不存在返回-1
        int res3 = message.lastIndexOf("l");
        System.out.println("res3 = " + res3);
        //截取字符串
        String s1 = message.substring(6); //从第六个字符开始截取,包括第六个字符
        System.out.println("s1 = " + s1);
        String s2 = message.substring(0,5); //截取第1个道第五个字符,左闭右开
        System.out.println("s2 = " + s2);
        //获取指定位置字符串
        char c =message.charAt(message.length()-1);
        System.out.println("c = " + c);
        //将字符串转化为char数组
        char [] chars = message.toCharArray();
        System.out.println(Arrays.toString(chars));
    }
}

image-20220922214732176

字符串常用方法三

image-20220922215134780

public class TestString2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String message = "你好世界";
        byte [] bytes = message.getBytes();
        System.out.println("Arrays.toString(bytes) = " + Arrays.toString(bytes));
        byte [] messBytes = message.getBytes("iso8859-1"); //这是统一标准
        System.out.println(Arrays.toString(messBytes));
        System.out.println(message.getBytes("gbk").length); //国标 一个汉字等于两个字节
        System.out.println(message.getBytes("utf-8").length); //一个汉字等于三个字节
    }
}

image-20220922221107346

starts with和ends with、正则表达式、replace函数、split函数

public class TestString2 {
    public static void main(String[] args) throws UnsupportedEncodingException {
        //判断以什么开头和以什么结尾
        String message = "I really want to stat at your house";
        boolean flag1 = message.startsWith("I");
        System.out.println("flag1 = " + flag1);
        boolean flag2 = message.endsWith("house");
        System.out.println("flag2 = " + flag2);
        //replace函数,替换第一个字符
        String rpmessage = message.replace("stat at your house","love you");
        System.out.println("rpmessage = " + rpmessage);
        //replaceall函数,替换所有字符,第一个参数可用正则进行匹配
        String message2 = "wo wo wo love you";
        String rpmessage2 = message2.replaceAll("wo","I");
        System.out.println("rpmessage2 = " + rpmessage2);
        //split函数分割字符串 可用正则匹配
        String s1 = "Fly1to1the1moon";
        String [] strings = s1.split("1");
        System.out.println(Arrays.toString(strings));
        //正则表达式进行匹配
        /*
        []:代表一个字符
        [a-z]:小写字母[a-z]任何一个都可以
        +: 一个或多个
        *: 0个或多个
        [^a]:代表匹配不是a的数据
        ^ :代表以什么开始
        $ : 代表以什么结尾
        \d:代表任意一个数字 0-9
        \w 代表数字字母和下划线
         */
        String s2 = "b";
        boolean matchs = s2.matches("[^a]");
        System.out.println("matchs = " + matchs);
    }
}

image-20220922225821274

day18

StringBuilder与StringBuffer

image-20221004210916260

image-20221004211139017

StringBuffer常用方法