java笔记

8 篇文章 0 订阅

java笔记目录

java程序运行机制

编译型:一次性编译完
解释型:边执行边编译

java基本语法

数据类型

基本数据类型

8个基本数据类型

数据类型中文类型占位字节大小值引用数据类型
boolean布尔类型逻辑性1字节1位ture和flaseBoolean
char字符类型文本型2字节16位0~65535Character
byte字节类型整数型1字节8位-128~127Byte
short短整型整数型2字节16位-32768~32767Short
int整型整数型4字节32位-231~231-1Integer
long长整型整数型8字节64位-263~263-1Long
float单精度浮点型4字节32位1.4E-45~3.4028235E38Float
double双精度浮点型8字节64位4.9E-324~1.7976931348623157E308Double

查看数据类型的最大值MAX_VALUE 最小值MIX_VALUE

//输出基本数据类型最大值
System.out.println(Integer.MAX_VALUE);

注意点 : long类型的值后面要加L, float类型的值后面要加F; char类型要用’'单引号,并且只能写一个字符

强制类型转换

在这里插入图片描述
自动类型转换 低->高
强制类型转换 高<-低
强制转换用法: (类型)变量名

注意点:
布尔值不能进行强转
强制转换可以能会造成 内存溢出

引用数据类型

默认初始值

小数类型 默认值 0
浮点数 默认值 0.0
boolean 默认值 false
char 默认值 '\u0000’空
引用数据类型(包括String) 默认值 null

扩展

浮点数

浮点数比较会存在误差 推荐使用大浮点数(BigDecimal)

float f1=0.1f;
double d1=0.1;
System.out.println(f1==d1); //输出false
char字符
char c1='A';
char c2=97; //会输出该数字对应的unicode编码字符
char c3='A';
System.out.println(c1);
System.out.println(c2);
System.out.println((int)c3);//强转
字符串

引用数据类型比较时:
    == 比较的是内存地址
    equals 比较的是数值

String s1=new String("hello world");
String s2=new String("hello world");
System.out.println(s1==s2);//返回false
System.out.println(s1.equals(s2));//返回true
boolean
boolean b1=true;
if (b1){
    System.out.println("会进入if判断");
}
转义字符

\t 制表符
\n 换行符

System.out.println("aaa\tbbb");//制表符
System.out.println("---------------");
System.out.println("ccc\nddd");//换行符

输出结果为:
在这里插入图片描述

变量

用法:
数据类型 变量名=值;

变量作用域

类变量 声明在类里面,并且是静态的 有默认初始值
实例变量 声明再类里面 有默认初始值
局部变量 声明在方法里面 没有默认初始值,必须初始化

public class 基本数据类型 {
    static int i1;  //类变量
    int i2; 	//实例变量

    public void method(){
        int i3; 	//局部变量
    }
}

常量

用 final 关键字来定义常量
常量初始化后 值不能再被改变
常量修饰在数组上时 数组里的值可以更改,数组的内存地址不能更改

final int i1=10;    //常量
static final int i2=10; //静态常量

命名规范

在这里插入图片描述

运算符

在这里插入图片描述
关系运算符返回的结果为布尔值

一元运算符

自增1和自减1
++n先加后输出
n++先输出后加

二元运算符

+ - * \ %

三元运算符

三元运算符也叫三目运算符
用法:
布尔表达式 ? 值1:值2
布尔值为true返回值1,false返回值2

int i1 = 10;
int i2 = 20;
String s1 = i1 == i2 ? "相等" : "不相等";

逻辑运算符

&& 逻辑与 两个结果都为真 结果为true
|| 逻辑或 只要有一个为真 结果就为true
逻辑 与或 有短路
按位 与或 没有短路

4个权限修饰符

privare私有的(最小的范围)只能被该类自身所访问和修改
default(默认的修饰符)只能被同一个包中的类访问
protected受保护的同一包中的类和在其他包中的该类的子类
public公共的在任何情况下都能被访问

一个java文件中只能有一个public公共类

javaDoc

在这里插入图片描述

scanner

接收键盘数据
在这里插入图片描述

public static void main(String[] args) {
    //创建一个扫描对象,用于接收键盘数据
    Scanner scanner = new Scanner(System.in);

    //使用next方式接收
    //scanner.next(); //接收的数据之间不能有空格
    //使用nextLine方式接收
    //scanner.nextLine(); //可以接收空格

    
    int b1 = 0;
    //判断接收的是否是int
    while (scanner.hasNextInt()){
        System.out.println(b1);
        
        //接收int类型
        b1=scanner.nextInt();
    }
    

    //判断是否还有输入
    boolean a = scanner.hasNext();
    System.out.println(a);
    boolean a1 = scanner.hasNextLine();  //判断有没有下一行数据
    System.out.println(a1);

    //关闭IO流
    scanner.close();
}

结构语句

分支

if

if(条件1){
//语句
}
else if(条件2)}{
//语句
}
else{
//语句
}

以上条件都不满足才执行else

switch

switch分支只支持byte short int char String类型(枚举),不支持long和小数类型

switch (变量){
	case1:
		//语句
		break;
	case2:
		//语句
		break;
	default:
		//语句
}

当case都不对则运行default
没有break也会执行这个
如果不写break就算满足条件也会继续往下执行
每句后面需要加break; 否则会继续往后执行

循环

for

for 知道循环次数用

for(1定义初始化参数;2布尔表达式;3更新迭代){
	//4循环内容
}

执行顺序 1-2-4-3-2-4-3…

增强for循环

主要用于迭代数组和集合

int numbers[]={1,5,5,34,4,5,5,7,3};
for (int i : numbers) {
    System.out.println(i);
}

将numbers数组中的每一项元素取出赋值给变量 i
i 表示每个元素,numbers 数组

while

while 不知道循环次数用

while(布尔表达式){
	//循环内容
}

do-while

do while 先执行后循环
while{
//循环内容
}do(布尔表达式)

break和continue

break跳出循环,结束循环
continue结束本次循环,继续下一次循环

break特殊用法:

abc:for(){
	break abc;//跳出名为abc的for循环,一般嵌套循环时用
}

递归

用递归实现n的阶乘

//求n的阶乘
public int test(int n) {
    if (n == 1) {
        return 1;
    } else {
        return n * test(n - 1);
    }
}

递归结构包括两个部分:
递归头: 什么时候不调用自身方法。如果没有头,将陷入死循环。
递归体:什么时候需要调用自身方法

大的数据不建议使用递归,容易造成内存崩溃

数组

声明数组

在类型后面加 [] 方括号

int[] i;	//首选方法
int i[];	//效果相同,不建议用

创建数组

创建数组时,必须定义数组长度

// =等号前面表示声明一个数组,= 后面表示创建数组,每一个元素都有默认初始值
写法一:int[] a=new int[5];	//首选方法
写法二:int[] a={23,431,43,34}	//练习时用
写法三:int a[]=new int[];	//一般不用

用法:

//声明并创建数组长度为10
int[] i=new int[10];
//给数组赋值
i[0]=10;
i[1]=20;
//从数组中取值
System.out.println(i[0]);
System.out.println(i[1]);
System.out.println(i[2]);//数组有默认值

需要理解
1. 数组的每一个元素都有默认初始值
2. 数组下标从0开始
3. 获取数组中的某一个元素 数组名[下标]
4. 获得数组长度 a.length
5. 创建数组后长度不能更改
6. 往数组里赋值 数组名[下标]=值
7. 数组是按引用数据类型传递的

多维数组

n维数组,是由多个n-1维数组 组成的 (如:二维数组是由多个一维数组组成)

创建二维数组:
String[][] a=new String[3][4]
该数组能放12个元素(最大一个数的下标为[2][3])
每个数有两个下标 a.length得到多少行 a[i].length得到某一行的列

稀疏数组

Arrays 数组类

数组的工具类常用方法:

  • toString 将数组元素以字符串形式返回
  • equals 比较数组里的元素是否相等
  • fill 快速填充
  • binarySearch 查找数组元素
  • sort 为数组排序
  • copyOf 复制
  • copyOfRange 截取
  • toCharArray 将字符串转换成字符数组
  • arraycopy 高级数组复制
//toString 将数组元素以字符串形式返回
String[] s1 = {"ad", "sf", "as", "nb"};
System.out.println(Arrays.toString(s1));
//输出结果  [ad, sf, as, nb]


//equals  比较数组里的元素是否相等
String[] s2 = {"ad", "sf", "as", "nb"};
System.out.println(Arrays.equals(s1, s2));
//输出结果 true
System.out.println(s1 == s2);// == 比较的是内存地址
//输出结果 false


//fill  快速填充
Arrays.fill(s2, "a");   //将s2数组中的元素全部设置为"a"
System.out.println(Arrays.toString(s2));
//输出结果 [a, a, a, a]


//binarySearch  查找数组元素
//数组内的元素需要排好顺序才能查找到(使用的是二分法查找)  //二分法查找数据(只能在排好顺序的情况下查找到)
int i4 = Arrays.binarySearch(s1, "sf"); //查找数组s1里没有没元素 "sf"
System.out.println(i4);     //返回该元素的下标,没找到返回负数
//输出结果 1


//sort  为数组排序
Arrays.sort(s1);    //传入数组
System.out.println(Arrays.toString(s1));
//输出结果  [ad, as, nb, sf]


//copyOf    复制
String[] s6 = Arrays.copyOf(s1, 5);//Arrays.copyOf(数组名,取几个值)  原数组值不够时补默认值
System.out.println(Arrays.toString(s6));
//输出结果  [ad, as, nb, sf, null]


//copyOfRange   截取
String[] s7 = Arrays.copyOfRange(s1, 2, 5);//从下标2开始截取,截取到下标5(不包括5)
System.out.println(Arrays.toString(s7));
//输出结果  [nb, sf, null]


//toCharArray   将字符串转换成字符数组
String a = "asdfghjkl";
char[] c1 = a.toCharArray();
System.out.println(Arrays.toString(c1));
//输出结果  [a, s, d, f, g, h, j, k, l]


//System方法
//arraycopy 高级数组赋值
String[] s8 = new String[10];
System.arraycopy(s1, 1, s8, 3, 3);//(原数组,原数组开始截取位置,放到那个数组里,放到新数组那个位置,截取原数组的长度(不能超过原数组长度))
System.out.println(Arrays.toString(s8));
//输出结果  [null, null, null, as, nb, sf, null, null, null, null]

java内存

在这里插入图片描述
只要是new的对象都会保存在堆内存中

声明数组时:数组将声明在 栈 里面
创建数组时:数组在 堆 里面创建大小
在这里插入图片描述

排序

冒泡排序法 两两比较,逆序则交换
选择排序法 每次选择最大值或最小值 (交换次数少,比冒泡效率高一点)
插入排序法
希尔排序法 效率最高,适合处理大数据

方法

用法:

修饰符 返回值 方法名(参数类型 参数名,多个参数用逗号隔开){
	方法体
}

return;返回

形参和实参

方法的参数 叫形参
调用方法时给他传的参数 叫实参
在这里插入图片描述

构造方法

规定

  1. 没有返回值
  2. 方法名和类名相同

类有默认有个无参构造
子类构造器里有默认的super()

new对象(创建对象)时自动调用,只能执行一次

构造方法设成私有的表示:这个类不能实例化(也就是不能new这个类)也不能有子类

方法的重载

方法名称相同,参数不同(类型不同,顺序不同,个数不同) 与权限和返回类型无关
重载的作用:调用方法时,有多个选择

方法的重写

只有子父类之间才能重写
要求 方法名称相同,参数相同,返回类型相同
规则 权限不能小,异常不能多
@Override表示该方法是重写方法

可变参数

在这里插入图片描述

public static void main(String[] args) {
	    class1 a1=new class1();
	    int[] i1= {3,4,5,2,1};
	    //a1.test();  //可以不传参数
	    a1.test(i1);  //可以传入数组参数
	    a1.test(12,14,4,5,2);   //也可以传入多个参数
	}
	
	public void test(int... ints){
	    System.out.println(ints[0]);	//需要用数组接收
	}

this关键字

this:本对象,谁调用方法,谁就是本对象就是thi

一个对象只有一次调用构造器的机会 ,方法能调用很多次

三个用法

  1. this.属性

    ​ 在方法中,this.访问成员变量和成员方法,有时可以省略
    ​ 当局部变量和成员变量命名冲突时,this表示访问成员变量,不可以省略

  2. this.方法()

    ​ this.方法名() 调用其他方法

  3. this()
    只能写在构造方法里,还必须写在第一行
    this()调用其他的构造方法(只能写在构造方法里,还必须写在第一行)
    ​ 在构造方法中,使用this(int a,int b)表示调用其他的构造方法,必须写在第一行

super

指代父类

点取父类属性
点取父类方法
调用父类构造器

用法一 super 当子类属性名和父类属性名一样时,用super找父类 super.属性名

用法二 super.方法名 找父类的方法

用法三 调用父类构造方法 (子类构造器里默认有个 super() 表示调用父类的构造器,当父类构造器有参数时,super()括号里需要写参数传给父类构造器)需要写在第一行
在这里插入图片描述

static静态的

共享内存,静态的内存只有一份

  • 修饰在属性上 叫 类属性
    1.共享内存,只有一块内存
    2.类名直接访问(类名.类变量)(只有本类型的可以访问,访问的是一块内存地址(静态区))

  • 修饰在方法上 叫 类方法
    类名可以直接访问(类名.类方法)

静态方法不实例化就能调用,普通方法必须实例化才可以调用
同一个类的对象使用不同的内存段,但静态成员共享相同的内存空间

规定

  1. 静态的只能访问静态的 非静态的能访问静态的
  2. 静态方法不能写this和super
  3. 构造方法不能写成静态的
  4. 局部变量不能写成静态的
  5. 静态的不能修饰类

final最终的

  • final只能修饰 类 方法 属性 局部变量

  • final修饰的类不能被继承
    final修饰的类能被重载
    final意思最终的(不能被修改)

  • final用在类里
    不能有子类 (添加在class前面)

  • final用在方法里
    不能被重写(子类不能有该方法)
    ​ 能被重载

  • final用在属性里
    不能在被再次赋值(值不能被修改)(final修饰后就是常量)(义时需要赋值,如果没有赋值,后面会有一次赋值机会,后面不能被修改)

  • final用在局部变量里
    不能在被赋值(定义时需要赋值,如果没有赋值,后面会有一次赋值机会,后面不能被修改)

instanceof

instanceof 判断两个类之间是否有父子关系
instanceof 判断对象是否是此类型,是-true(兄弟类不能强转)
a instanceof Dog(对象变量 intanceof 类型)

执行顺序

父类静态属性–父类静态代码块->子类静态属性–子类静态代码块->父类非静态属性->父类非静态代码块->父类的构造方法->子类非静态属性->子类非静态代码块->子类的构造方法
静态属性和静态代码块是按照书写循序执行的,属性跟代码块也是按照书写顺序执行

传递

基本数据类型 按值传递
数值的copy,两个值,一个值修改了,另一个值不变

引用数据类型 按引用传递
内存地址的copy,两个变量,指向同一个内存地址,一个值修改了,另一个值也随之改变

  • 基本数据类型:按值传递; (值传递栈内存,数据存在栈内存里)
  • 引用数据类型:按引用传递; (引用,数据存在堆内存里,地址存在栈内存)(引用就是内存地址)
  • 引用传递就是把内存地址传过去,值传递就是传值

引用数据类型,比的是内存地址
希望比的是数据就用equals方法

类和对象

类是抽象的,对象是具体的
类只有一个,对象能有多个(对象名不能一样)
在这里插入图片描述
类名 对象(类实例)=new 类名();(可以new子类)
A a=new A();
A表示一个类(也是一个类型 )
a表示对象
a是A类的类实例

类都默认有个Object父类

封装/继承/多态

继承

extends 继承(单继承,子类只能有一个父类,父类可以有多个子类,)
extends 父类
子类将继承父类的非私有属性和方法

多态

父类的引用指向子类的地址
父类 c=new 子类();
new谁就调用谁的方法 多态的强制类型转换 多态的作用是提高可重用性,扩展代码模板

常用类

抽象类和接口

abstract 抽象

用在类上 定义为抽象类
抽象类中的抽象方法,继承了他的子类,都必须要实现他的抽象方法~除非子类也是抽象类

用在方法上 抽象方法:

  • 没有方法体
  • 包含抽象方法的类一定是抽象类(抽象类里不一定是抽象方法)
  • 用abstract修饰的类,就是抽象类
  • 抽象类不能new对象的(不能创建对象)(不能实例化)
  • 父类是抽象的,子类需要把父类的抽象方法重写~除非子类也是抽象类
  • 继承抽象类,子类必须重写(实现)父类的抽象方法
  • 可以有构造方法
  • 抽象类:只有定义,不能实现
    在这里插入图片描述

接口

interface 定义接口

接口规则:

  1. 接口里的所有方法都是抽象方法
    1. 8.0版本以后 (默认方法和静态方法)接口可以带方法体
    2. default 默认方法 可以带方法体(可以不实现)
    3. static 静态方法 可以带方法体(可以不实现)
    4. 可以接口直接调用方法
      1. 接口.方法
  2. 接口里方法必须都是公共(public)的(接口里方法默认也是公共的)
  3. 接口不能new对象的(不能创建对象)
  4. 接口不能写构造器(没有构造器)
  5. 接口中的属性默认都是公共的 静态(static) 常量(final) 必须赋值
  6. 接口可以继承接口
  7. 一个类可以实现多个接口
  8. 一个接口可以继承多个接口,类也可以继承多个接口
  9. 接口不能实现接口,只有类才能实现接口

用 implements 实现接口

继承和实现同时写时
继承在前实现在后(规定)

函数式接口

函数式接口(有且仅有一个抽象方法)@FunctionalInterface

public interface JieKou1 {//函数式接口
    abstract void j1();//抽象方法(abstract可以省略)
    default void j2(){
        //默认方法
    }
    static void j3(){
        //静态方法
    }
}

异常

在这里插入图片描述
运行时异常:都是RuntimeException类及其子类异常,如NullPointerException(空指针异常)、IndexOutOfBoundsException(下标越界异常)等,这些异常是不检查异常,程序中可以选择捕获处理,也可以不处理。这些异常一般是由程序逻辑错误引起的,程序应该从逻辑角度尽可能避免这类异常的发生。
运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过。
非运行时异常 (编译异常):是RuntimeException以外的异常,类型上都属于Exception类及其子类。从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过。如IOExceptionSQLException等以及用户自定义的Exception异常,一般情况下不自定义检查异常

处理异常的5个关键字
try catch finally throw throws

try {
    //try监控区域
}catch (Exception e){
    //捕获异常
}finally {
    //不管有没有异常都会执行
}
void test() throws Exception {
    throw new Exception();
}

//throw 主动抛出异常,写在方法里面
//throws 方法抛出异常,写在方法上

常用类

Object

Object 是所有java类的根父类,所有类默认继承Object类

toString() 将对象转换成字符串
equals() 比较两个对象是否相等
hashCode() 将对象转换成哈希码

String

  • String(char[] c) 将字符数组转换成字符串
  • length() 取得字符串的长度
  • equals(Object s) 比较两个对象是否相等
  • equalsIgnoreCase(String s) 忽略大小写比较两个String对象是否相等
  • compareTo 比较两个字符串的大小,比较的是字符的ascii表
  • compareToIgnoreCase 忽略大小写比较
  • startsWith 测试此字符串是否以指定的前缀开始
  • endsWith 测试此字符串是否以指定的后缀结束

字符串检索

  • charAt 根据下标找指定字符
  • indexOf 返回指定字符的下标
  • lastIndexOf 返回指定字符的下标,从后往前找

截取字符串

  • substring 截取字符串
  • trim 去掉两边的空格

替换

  • replace 替换
  • toUpperCase 小写字母转成大写字母
  • toLowerCase 大写字母转成小写字母

字符串分解成数组

  • getBytes 将字符串转换成字节数组
  • toCharArray 将字符串转换成字符数组
  • split 拆分
//String()  将字符数组转换成字符串
char[] c1 = {'a', 's', 'f', '1', 't'};
String str = new String(c1);
System.out.println("String()=   " + str);


//length()  取得字符串的长度
System.out.println("length()=   " + str.length());


//equals(Object s)  比较相等
//equalsIgnoreCase(String s)    忽略大小写比较
String a2 = "ABcd";
String b2 = "abcd";
//比较两个对象的实体是否相等(返回布尔值)
System.out.println("equals= " + a2.equals(b2));
//比较两个 String 对象的值是否相等,忽略大小写
System.out.println("equalsIgnoreCase= " + a2.equalsIgnoreCase(b2));


//compareTo 比较大小
//compareToIgnoreCase   忽略大小写比较
String a3 = "Abc";
String b3 = "abd";
//比较两个字符串的大小。返回0表示相等,比的是阿斯克码表,先比第一个字符
//返回大于0的数表示前面的字符串大于后面的字符串
//返回小于 0 表示前面的字符串小于后面的字符串
System.out.println("compareTo= " + a3.compareTo(b3));
//忽略大小写,比较两个字符串的大小
System.out.println("compareToIgnoreCase= " + a3.compareToIgnoreCase(b3));


//startsWith    前缀开始
//endsWith    后缀结束
String a4 = "李四";
//测试此字符串是否以指定的前缀开始
System.out.println("startsWith= " + a4.startsWith("李"));
//测试此字符串是否以指定的后缀结束
System.out.println("endsWith= " + a4.endsWith("泽伟"));
//判断是否以指定的前缀开始,如果是,返回true,否则返回false


//isEmpty   判断字符串是否为空
System.out.println("isEmpty=    " + a4.isEmpty());


//-------字符串检索-------


//charAt    根据下标找指定字符
String a5 = "asdfasdf";
//输出下标为4的字符(输入的下标超出则抛出StringIndexOutOfBoundsException异常)
System.out.println("charAt= " + a5.charAt(4));


//indexOf   返回指定字符的下标
//lastIndexOf   从后往前找,返回指定字符的下标
String s6 = "ashwoalgvnoaweAAAAA";
//indexOf用法一:在字符串中查找字符串,返回找到字符串的下标(第一次),
System.out.println("indexOf= " + s6.indexOf("w"));
//用法二:从指定的索引开始搜索,返回在此字符串中第一次出现指定字符处的索引
System.out.println("indexOf= " + s6.indexOf("w", 5));//从下标5开始往后搜索w
//lastIndexOf方法:在字符串中查找字符串,返回找到字符串的下标(最后一次)
System.out.println("lastIndexOf= " + s6.lastIndexOf("w"));
//如果没有找到,返回-1


//contains  查询是否包含该字符
System.out.println("contains=   " + s6.contains("v"));//查询字符串中是否有v字符


//--------截取字符串--------


//substring 截取字符串
String s8 = "ashwoalgvnoaweAAAAA";
System.out.println("substring= " + s8.substring(3));//substring方法:截取字符串,从开始参数(下标)截取到最后
//substring方法:截取字符串,从开始参数到结束参数,包含开始位置,不包含结束位置。(返回新的字符串)
System.out.println("substring= " + s8.substring(3, 9));

//trim  去掉两边的空格
String a9 = "  1 2  2   ";
System.out.println(a9.trim());
//返回新字符串,截去了源字符串最前面和最后面的的空白符;如果字符串没有被改变,则返回源字符串的引用


//-------替换-------


//replace 替换
//replaceAll    根据正则表达式替换
String a10 = "javakc91javakc92javakc93";
System.out.println(a10.replace("9", "*"));
System.out.println(a10.replaceAll("\\d", "*"));//支持正则表达式
//返回一个新的字符串,源字符串没有发生变化
//它是将字符串中的所有oldChar替换成newChar
//如果该字符串不含oldChar, 则返回源字符串的引用。
String s = "  java kc  ";
//将全部空格替换成空字符串,即将所有空格删除
System.out.println(s.replace(" ", ""));

//toUpperCase   小写字母转成大写字母
//toLowerCase   大写字母转成小写字母
String s11 = "ashwoalgvnoaweAAAAA";
//toUpperCase方法:小写字母转成大写字母
System.out.println(s11.toUpperCase());
//toLowerCase方法:大写字母转成小写字母
System.out.println(s11.toLowerCase());//toLowerCase方法:大写字母转成小写字母
//返回对应的新字符串,所有小写字母都变为大写的,其它的不变。
//如果没有字符被修改,则返回字符串的引用


//------字符串分解成数组------


//getBytes  将字符串转换成字节数组
String a12 = "abc";
byte[] b12 = a12.getBytes();//使用平台的默认字符集将此String 编码为byte序列,并将结果存储到一个新的byte 数组中。//中文占两位,(或三位,根据字节编码占位)
System.out.println(Arrays.toString(b12));

//toCharArray   将字符串转换成字符数组
char[] c = a12.toCharArray();//将此字符串转换为一个新的字符数组
System.out.println(Arrays.toString(c));

//split拆分
String a13 = "王聪-王镇-王康-李昊冉";
String[] b13 = a13.split("-");//按照特定字符分割成字符串数组
for (String s13 : b13) {//循环输出数组
    System.out.println(s13);
}
//拆分特殊符号要加转义符,(如.)
//根据给定正则表达式的匹配拆分此字符串,得到拆分好的字符串数组

StringBuffer动态字符串类

StringBuffer目的是用来解决字符串相加时带来的性能问题
Stringbuffer内部采用的是字符数组,默认数组长度是16,超过数组大小时,动态扩充的算法是原数组长度*2+2
可以在创建StringBuffer时自己设置长度
StringBuffer是线程安全的

  • append 用来连接字符串,追加数据
  • delete 删除指定区间的字符
  • insert 在指定位置插入
  • length 获得长度
  • indexOf 查找下标对应的字符
  • reverse() 字符串反转
  • capacity 查看StringBuffer的容量
  • setLength 设置长度,增加或减小StringBuffer的长度
  • CharAt 返回下标对应的字符
  • setCharAt 替换,传入下标位置,替换成指定字符
  • getChars() 截取放到一个新的char数组中
StringBuffer sb=new StringBuffer("aaa");

//append 用来连接字符串,追加数据
sb.append("1234567893");

//delete    删除指定区间的字符
sb.delete(3,6);    //删除下标开始到结束(不包括结束下标)的字符
System.out.println(sb);

//insert      在指定位置插入
sb.insert(3,"abc");//把abc插入到下标3的位置
System.out.println(sb);

//length      获得长度
System.out.println(sb.length());

//indexOf   查找下标对应的字符
System.out.println(sb.indexOf("3",4));

//reverse()   字符串反转
System.out.println(sb.reverse());

//capacity    查看StringBuffer的容量
System.out.println(sb.capacity());

//setLength  设置长度,增加或减小StringBuffer的长度
sb.setLength(9);
System.out.println(sb);

//CharAt    返回下标对应的字符
System.out.println(sb.charAt(4));

//setCharAt   替换,传入下标位置,替换成指定字符
sb.setCharAt(6,'F');
System.out.println(sb);

//getChars() 截取放到一个新的char数组中
char[] dst=new char[10];
sb.getChars(4,9,dst,0);//开始截取位置,结束位置,放到哪里,从下标几开始放
System.out.println(dst);

StringBuffer和StringBuildr

Buffer线程安全的 效率低
Builer线程不安全的 效率高

Math数学类

  • PI 圆周率
  • E 自然对数
  • ceil 天花板数,返回不小于他的最小整数
  • floor 地板数,返回不大于他的最大整数
  • round 四舍五入
  • abs 绝对值
  • min 最小值
  • max 最大值
  • sqrt 平方根
  • random 随机数
//圆周率
System.out.println(Math.PI);
//自然对数
System.out.println(Math.E);

double d1=3.1415;
double d2=3.149;
//ceil	天花板数,返回不小于他的最小整数
System.out.println(Math.ceil(d1));

//floor	地板数,返回不大于他的最大整数
System.out.println(Math.floor(d1));

//round	四舍五入
System.out.println(Math.round(d1));

//abs 	绝对值
System.out.println(Math.abs(d1));

//min   最小值
//max   最大值
System.out.println(Math.min(d1, d2));
System.out.println(Math.max(d1, d2));

//sqrt	平方根
System.out.println(Math.sqrt(d1));

//random    随机数
System.out.println(Math.random());

Date日期类

需要掌握:
new Date() 获得当前时间
format() 日期转换成指定格式
parse() 字符串转成日期类型

//创建日期对象,获得当前时间
Date date = new Date();
System.out.println(date);
//输出结果  Fri Apr 08 20:52:21 CST 2022

//格式化日期,日期转换成指定格式
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EE");
String str = sdf.format(date);
System.out.println(str);
//输出结果  2022-04-08 20:52:21 星期五

//字符串转成日期类型
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss EE");
Date date1 = sdf1.parse(str);
System.out.println(date1);
//输出结果  Fri Apr 08 20:52:21 CST 2022

getTime() 将日期类型转换成毫秒数

System.out.println(date.getTime());

currentTimeMillis() 获得当前时间毫秒数

System.out.println(System.currentTimeMillis());

new Date(long date) 毫秒数转日期

long date2 = System.currentTimeMillis();
System.out.println(new Date(date2));

大整数BigInteger

大浮点数BigDecimal

BigDecimal decimal = new BigDecimal(20.02);
BigDecimal decimal1 = new BigDecimal(30.03);

//加法
System.out.println(decimal.add(decimal1));
//减法
System.out.println(decimal.subtract(decimal1));
//乘法
System.out.println(decimal.multiply(decimal1));
//除法
System.out.println(decimal1.divide(decimal, 3, BigDecimal.ROUND_HALF_UP)); //小数后保留3位,BigDecimal.ROUND_HALF_UP四舍五入
//转成int类型
int i = decimal.intValue();
//绝对值
System.out.println(decimal.abs());

基本数据类型包装类

基本数据类型转换为引用数据类型 装箱
引用数据类型转换为基本数据类型 拆箱
拆箱装箱都可以自动完成

将String类型的数字转换成int类型

//把数值字符串转换成int类型
String num="12";
int i=Integer.parseInt(num);//方法一
int i1=Integer.valueOf(num);//方法二

parseFloat 转换为float类型
引用数据类型.valueOf 转换成指定的数据类型

内部类

内部类和静态内部类

public class Outer {
    private int id = 10;

    public void out() {
        System.out.println("这是外部类中的方法");
    }

    //内部类
    public class inner {
        public void in() {
            System.out.println("这是内部类中的方法");

            //获得外部类的私有属性
            System.out.println("获得外部类中的属性:" + id);
        }
    }

    //静态内部类
    public static class inner1 {
        public void in() {
            System.out.println("这是静态内部类中的方法");
        }
    }
}

class Test {
    public static void main(String[] args) {
        //实例化外部类
        Outer outer = new Outer();

        //通过外部类来实例化内部类
        Outer.inner inner = outer.new inner();
        inner.in();
    }
}

两种排序方式

CompareTo自然排序

用来实体类中,使用方法:
实现Comparable接口,重写方法

//按照name从小到大排序,其次按照age排序
@Override
    public int compareTo(Object o) {
        if (o instanceof User) {
            User user = (User) o;

            int compare = this.name.compareTo(user.name);
            //从大到小
            //-this.name.compareTo(user.name);
            if (compare != 0) {
                return compare;
            } else {
                return Integer.compare(this.age, user.age);
            }
        } else {
            throw new RuntimeException("输入的类型不匹配");
        }
    }

定制排序

集合

  • collection
    • List
      • ArrayList
      • LinkedList
      • Vector
    • Set
      • HashSet
      • LinkedHashSet
      • TreeSet
  • Map
    • HashMap
    • LinkedHashMap
    • TreeMap
    • Hashtable
    • Properties

Collection

向Collection接口的实现类中添加对象时,要求重写对象的equels()方法

常用方法一

  • add() 添加元素
  • size() 获取集合中元素的个数
  • addAll() 把一个集合的元素添加到一个新的集合
  • isEmpty() 判断当前集合是否为空,判断的是集合中是否有元素
  • contains() 判断是否包含
  • containsAll() 判断集合coll1中是否包含coll集合中的所有元素
  • remove() 删除指定元素
  • removeAll() 删除当前集合中包含另一个集合中的所有元素
  • clear() 清空集合中的元素
Collection coll = new ArrayList();

//add() 添加元素
coll.add("AA");
coll.add(123);
coll.add(new Date());
coll.add(new String("BB"));

//size() 获取集合中元素的个数
System.out.println(coll.size());

//addAll()  把一个集合的元素添加到一个新的集合
Collection coll1 = new ArrayList();
coll1.add(456);
coll1.addAll(coll);


//isEmpty() 判断当前集合是否为空,判断的是集合中是否有元素
System.out.println(coll.isEmpty());//返回true表示没有元素

//contains() 判断是否包含
System.out.println(coll.contains(123));

//containsAll()   判断集合coll1中是否包含coll集合中的所有元素
System.out.println(coll1.containsAll(coll));

//remove()  删除指定元素
coll1.remove(123);  //删除成功返回true,没找到返回false
System.out.println(coll1);

//removeAll()   删除当前集合中包含另一个集合中的所有元素
coll1.removeAll(coll);
System.out.println(coll1);

//clear()   清空集合中的元素
coll.clear();

常用方法二

  • retainAll() 获取两个集合的交集
  • equels() 比较两个集合是否相等
  • hashCode() 返回当前对象的哈希值
  • toArray() 集合转成数组
  • Arrays.asList() 数组转成集合
Collection coll = new ArrayList();

//add() 添加元素
coll.add("AA");
coll.add(123);
coll.add(new Date());
coll.add(new String("BB"));

Collection coll1 = new ArrayList();
coll1.add(123);
coll1.add("AA");

//retainAll()   获取两个集合的交集
coll.retainAll(coll1);
System.out.println(coll);

//equels()  比较两个集合是否相等
System.out.println(coll.equals(coll1));

//hashCode()    返回当前对象的哈希值
System.out.println(coll.hashCode());

//toArray() 集合转成数组
Object[] o = coll.toArray();
System.out.println(Arrays.toString(o));

//插入多个元素    Arrays.asList()
//数组插入到集合里    Arrays.asList()
System.out.println(Arrays.asList(o));

iterator()迭代器和foreach

  • iterator() 迭代器
  • next 获得下一个元素
  • hasNext() 判断是否有下一个元素
  • foreach 循环每一个元素
Collection coll = new ArrayList();
        //add() 添加元素
        coll.add("AA");
        coll.add(123);
        coll.add(new Date());
        coll.add(new String("BB"));

        //iterator()   迭代器
        Iterator iterator = coll.iterator();
        //next 获得下一个元素
        System.out.println(iterator.next());
        System.out.println(iterator.next());

        //hasNext() 判断是否有下一个元素
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        
        //foreach
        //for(集合中的每一个元素 : 集合对象)
        for (Object o : coll) {
            System.out.println(o);
        }

List

有下标,可重复
ArrayList 线程不安全;效率高;底层使用Objec[]数组存储
LinkedList 线程不安全;效率高;底层使用双向链表存储
Vector 线程安全;效率低;底层使用Objec[]数组存储

list常用方法:

  • add(int index,Object ele) 将元素插入到指定位置
  • addAll(int index,Cellection eles) 将一个集合中的所有元素插入到指定位置
  • get(int index) 传入下标获得指定元素
  • indexOf 返回指定元素的下标,没找到返回-1
  • lastIndexOf 返回指定元素的下标,没找到返回-1,最后出现的位置
  • remove(int index) 根据下标删除元素
  • set(int index,Object ele)替换
  • subList(int fromIndex,inttoIndex) 传入下标,获得指定区间的元素
ArrayList list = new ArrayList(100);
list.add(123);
list.add(456);
list.add(new String("AA"));
list.add(456);
System.out.println(list);

//add(int index,Object ele) 将元素插入到指定位置
list.add(2, "BB");
System.out.println(list);

//addAll(int index,Cellection eles) 将一个集合中的所有元素插入到指定位置
List list1 = Arrays.asList(1, 2, 3);
list.addAll(1, list1);
System.out.println(list);

//get(int index)    传入下标获得指定元素
System.out.println(list.get(3));

//indexOf 返回指定元素的下标,没找到返回-1
System.out.println(list.indexOf(456));

//lastIndexOf   返回指定元素的下标,没找到返回-1,最后出现的位置
System.out.println(list.lastIndexOf(456));

//remove(int index) 根据下标删除元素
list.remove(4);
System.out.println(list);

//set(int index,Object ele)替换
list.set(1, "5");//下标,替换后的元素
System.out.println(list);

//subList(int fromIndex,int toIndex) 获得指定区间的元素
List list2 = list.subList(2, 6);
System.out.println(list2);

set

HashSet 线程不安全;可以存null值
LinkedHashSet 是HashSet的子类;遍历内部数据时,可以按照添加顺序遍历
TreeSet 可以按照添加对象的指定属性,进行排序

HashSet
HashSet底层使用的是HashMap集合

向set中添加数据一定要重写equals()和hashCode()方法
无序,没有下标,不可重复
无序性: 储存的数据在底层数组中并非并非按照数组索引顺序添加,而是根据数据的哈希值决定的
不可重复性: 元素按照equels()方法和Hash方法进行判断

LinkedHashSet
LinkedHashSet作为HaSet的子类,在添加数据时,每个数据还维护了两个引用,记录前一个数据和后一个数据
优点:对于比较频繁的遍历操作,LinkedHashSet效率高于HashSet

TreeSet
只能添加相同类型的对象
输出是会默认按照顺序排好
在这里插入图片描述

map

map无序;key不能重复,value可以重复;
HashMap:线程不安全,效率高;可以存null的key和value;底层使用数组+链表+红黑树
LinkedHashMap:遍历map元素时,会按照添加顺序进行遍历;对于频繁的遍历操作,此类执行效果高于HashMap
TreeMap:按照添加的key-value进行排序,按照key进行排序;底层使用红黑树
Hashtable:线程安全,效率低;不能存null的key和value
Properties:常用来处理配置文件,key和value都是String类型

HashMap底层实现原理:
在这里插入图片描述
在这里插入图片描述
底层扩容机制,是根据临界值进行扩容,当超出临界值并且存放的位置非空时,扩容,扩容为原来的2倍
在这里插入图片描述

Map中常用的方法:

增删改操作

Map map=new HashMap();

//put 添加
map.put("AA",123);
map.put("BB",123);
map.put("CC",123);
//put 修改
map.put("AA",456);
System.out.println(map);
//输出结果{AA=456, BB=123, CC=123}

Map map1=new HashMap();
map1.put("TT",987);
map1.put("RR",457);
//putAll(Map m) 将一个Map集合中的所有元素添加到当前map中
map.putAll(map1);
System.out.println(map);
//输出结果{AA=456, BB=123, CC=123, TT=987, RR=457}

//remove(Object key)    根据key删除
map.remove("TT");
System.out.println(map);
//输出结果{AA=456, BB=123, CC=123, RR=457}

//clear()   清空
map.clear();
System.out.println(map);
//输出结果{}

查询

Map map=new HashMap();
map.put("AA",123);
map.put("BB",123);
map.put("CC",123);

//get(Object key)   根据指定key获得value
System.out.println(map.get("AA"));
//输出结果:123

//containsKey(Object key)   查询是否包含指定key
System.out.println(map.containsKey("AA"));
//输出结果:true

//containsKey(Object vlaue)   查询是否包含指定key
System.out.println(map.containsValue(123));
//输出结果:true

//size()    获得map中key-value对的个数
System.out.println(map.size());
//输出结果:3

//isEmpty() 判断是否为空
System.out.println(map.isEmpty());
//输出结果:false


Map map1=new HashMap();
map1.put("AA",123);
map1.put("BB",123);
map1.put("CC",123);
//equels() 比较两个map是否相等
System.out.println(map.equals(map1));
//输出结果:true

遍历Map

Map map = new HashMap();
map.put("AA", 123);
map.put("BB", 456);
map.put("CC", 789);

//遍历所有的key 放到set集合中
Set set = map.keySet();
for (Object o : set) {
    System.out.println(o);
}

//遍历所有的value 放到Collection集合中
Collection value=map.values();
for (Object o : value) {
    System.out.println(o);
}

//获得key和value,通过key获得value
for (Object o : set) {
    System.out.println(o);//遍历key
    System.out.println(map.get(o));//遍历value
}

Collections工具类

collection是一个操作Set List和Map等集合的工具类

List list = new ArrayList();
list.add(123);
list.add(456);
list.add(780);
list.add(725);
list.add(472);
list.add(123);
System.out.println(list);
//输出结果:[123, AAA, ABC, 456, 780]

//reverse() 反转List中的元素
Collections.reverse(list);
System.out.println(list);
//输出结果:[780, 456, ABC, AAA, 123]

//shuffle() 对list集合中的元素随机排序
Collections.shuffle(list);
System.out.println(list);
//输出结果,每次输出得都不一样:[AAA, 123, 456, 780, ABC]

//sort()    根据自然排序对list中的元素进行排序
Collections.sort(list);
System.out.println(list);
//输出结果:[123, 456, 472, 725, 780]

//swap  将list中的两个元素进行交换
Collections.swap(list, 2, 3);
System.out.println(list);
//输出结果:[123, 456, 725, 472, 780]

//min() max() 获取list中的最小值和最大值
System.out.println(Collections.min(list));
System.out.println(Collections.max(list));

//frequency()   //查询指定元素出现的频率
System.out.println(Collections.frequency(list, 123));
//输出结果:2

//copy //将集合中的元素复制到一个新的集合中

//将线程不安全集合,改成线程安全的
List list1 = Collections.synchronizedList(list);//返回的list1集合为安全的集合

注解

@Override 重写注解
@Deprecated 过时的

元注解(用来规定注解)

//@Target 描述注解可以用在那些地方
@Target(value = {ElementType.METHOD})
//@Retention 表示注解在什么地方有效 runtime->class->sourecs
@Retention(value = RetentionPolicy.RUNTIME)
//Documented    表示是否将我们的注解生成在JAVAdoc中
@Documented
//@Inherited 子类可以继承父类的注解
@Inherited 
//@interface 定义该类为注解类
@interface MyAnnotation{

}

@Target注解的参数:
TYPE 可以修饰类,接口(包括注解类型),或者枚举
FIELD 字段枚举常量
METHOD 修饰方法
PARAMETER 修饰参数
CONSTRUCTOR 修饰构造方法
LOCAL_VARIABLE 修饰局部变量
ANNOTATION_TYPE 修饰注解类型
PACKAGE 修饰包
TYPE_PARAMETER 修饰类型参数
TYPE_USE 可以修饰任何类型

@Retention 的参数
在这里插入图片描述
注解的参数:

@Target(value = {ElementType.METHOD})
@Retention(value = RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    //注解的参数写法:参数类型 参数名();
    String value();
    //default 设置参数的默认值
    String value2() default "";
}

反射

在这里插入图片描述

获得Class对象

//获得Class对象
//方式一:通过对象获得
User user = new User();
Class c1 = user.getClass();

//方式二:forName
Class c2 = Class.forName("User");//输入对象的全路径

//方式三:通过类名.class获得
Class c3 = User.class;

System.out.println(c1);
System.out.println(c2);
System.out.println(c3);

//通过Class对象获得父类对象
System.out.println(c1.getSuperclass());

类的被动引用:
在这里插入图片描述

获得Class对象和类的名字

//获得Class对象
Class<?> user = Class.forName("com.kuang.User");

//获得类的名字
System.out.println(user.getName()); //获得包名+类名
System.out.println(user.getSimpleName());   //获得类名

获得类的属性

//获得Class对象
Class<?> user = Class.forName("com.kuang.User");

//获得了类的属性
Field[] fields = user.getFields();  //只能获得public属性
System.out.println(Arrays.toString(fields));
Field[] declaredFields = user.getDeclaredFields();//获得全部属性
for (Field declaredField : declaredFields) {
    System.out.println(declaredField);
}
//获得指定属性的值
//getField("属性名")
System.out.println(user.getField("s")); //只能获得public属性
System.out.println(user.getDeclaredField("name"));

获得类的方法

//获得Class对象
Class<?> user = Class.forName("com.kuang.User");

//获得类的方法
Method[] methods = user.getMethods();//获得本类和父类的所有public方法
for (Method method : methods) {
    System.out.println("getMethods:" + method);
}

System.out.println("================华丽的分割线================");

Method[] declaredMethods = user.getDeclaredMethods();//获得本类的所有方法
for (Method declaredMethod : declaredMethods) {
    System.out.println("getDeclaredMethods:" + declaredMethod);
}

System.out.println("================华丽的分割线================");

//获得指定方法
//getMethod("方法名",方法参数类型.class)
Method getName = user.getMethod("getName", null);//getDeclaredField获得所有方法
Method setName = user.getMethod("setName", String.class);
System.out.println(getName);
System.out.println(setName);

System.out.println("================华丽的分割线================");

//获得指定的构造器
Constructor[] constructors = user.getConstructors();//获得public构造器
for (Constructor constructor : constructors) {
    System.out.println(constructor);
}
System.out.println("++++++分割线+++++");
Constructor[] declaredConstructors = user.getDeclaredConstructors();//获得全部构造器
for (Constructor declaredConstructor : declaredConstructors) {
    System.out.println(declaredConstructor);
}
System.out.println("++++++分割线+++++");
//获得指定的构造方法
Constructor<?> declaredConstructor = user.getDeclaredConstructor(String.class, int.class);
System.out.println(declaredConstructor);

通过构造器创建对象

//获得Class对象
Class<?> user = Class.forName("com.kuang.User");

//通过无参构造创建一个对象
User user1 = (User) user.newInstance();
System.out.println(user1);
//前提需要满足两个条件:1.必须有无参构造;2.无参构造权限必须足够

//通过有参构造创建一个对象
Constructor<?> declaredConstructor = user.getDeclaredConstructor(String.class, int.class);
User user2 = (User) declaredConstructor.newInstance("安", 20);
System.out.println(user2);

通过反射操作方法

//获得Class对象
Class<?> user = Class.forName("com.kuang.User");

//通过反射操作方法
//1.创建对象
User user1 = (User) user.newInstance();
//2.获取方法
Method setName = user.getDeclaredMethod("setName", String.class);
//3.调用(激活)方法
//invoke(对象,"方法参数")
setName.invoke(user1,"安鹏");
System.out.println(user1.getName());

通过反射操作属性

//获得Class对象
Class<?> user = Class.forName("com.kuang.User");

//通过反射操作属性
//1.获得对象
User user1 = (User) user.newInstance();
//2.获得属性
Field name = user.getDeclaredField("name");
//不能直接操作私有属性,反射里可以直接操作,但需要关闭程序的安全检测
name.setAccessible(true);//默认为false,设置为true即为关闭

//3.赋值
name.set(user1,"安");
System.out.println(user1.getName());

setAccessible()方法

在这里插入图片描述

多线程

三种创建方式:
继承Thread类
实现Runnable接口
实现Callable接口

继承Thread类创建多线程

1.继承Thread类
2.重写run()方法
3.调用start开启线程

//1.继承Thread类
public class ThreadTest extends Thread {
	//2.重写run()方法
    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            System.out.println(i);
        }
    }

    public static void main(String[] args) {
        ThreadTest threadTest=new ThreadTest();
        //3.调用start开启线程
        threadTest.start();
    }
}

实现Runnable接口创建多线程

//1.实现Runnable接口
public class ThreadTest2 implements Runnable {
    //2.重写run方法
    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            System.out.println(i);
        }
    }

    public static void main(String[] args) {
        //3.创建Runnable接口的实现类对象
        ThreadTest2 test = new ThreadTest2();
        //4.创建线程对象,通过线程对象来开启线程,代理
        Thread thread = new Thread(test);//把实现类传进去
        //5.调用start()方法开启线程
        thread.start();
    }
}

多个线程同时操作一个对象

未加同步块有线程并发问题

//多个线程同时操作一个对象
//买火车票例子
public class ThreadTest3 implements Runnable {
    //票数
    private int ticketNumber = 20;

    @Override
    public void run() {
        while (true) {
            if (ticketNumber <= 0) {
                break;
            }

            //模拟延迟
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //Thread.currentThread().getName()拿到当前线程的名字
            System.out.println(Thread.currentThread().getName() + "-->拿到了第" + ticketNumber + "张票");
            ticketNumber--;
        }
    }

    public static void main(String[] args) {
        ThreadTest3 threadTest3 = new ThreadTest3();
        new Thread(threadTest3, "线程的名字,线程一").start();
        new Thread(threadTest3, "线程二").start();
        new Thread(threadTest3, "线程三").start();
    }
}

线程状态及声明周期

线程的五大状态
在这里插入图片描述
在这里插入图片描述

stop 停止线程

/**
 * 测试stop
 * 1.建议线程正常停止 --> 利用次数,不建议死循环
 * 2.建议使用标志位 --> 设置一个标志位
 * 3.不建议使用stop或者destroy等过时的方法或者JDK不建议使用的方法
 */
public class StopTest implements Runnable {
    //设置一个标志位
    boolean flag=true;

    @Override
    public void run() {
        int i = 0;
        while (flag) {
            System.out.println(i++);
        }
    }

    //设置一个公开的方法转换标志位,来停止线程
    public void stop() {
        this.flag = false;
    }

    public static void main(String[] args) {
        StopTest stopTest = new StopTest();
        new Thread(stopTest).start();
        for (int i = 0; i <= 100000; i++) {
            if (i>=100000){
                //调用转换标志位方法,来停止线程
                stopTest.stop();
                System.out.println("线程该停止了");
            }
        }
    }
}

sleep线程休眠

主要用来:模拟网络延迟 -> 放大问题的发生性
模拟倒计时

yield线程让步

让当前正在运行的线程暂停,让系统的调度器重新调度一次

@Override
public void run() {
    System.out.println(Thread.currentThread().getName()+"线程开始");
    //线程让步
    Thread.yield();
    System.out.println(Thread.currentThread().getName()+"线程结束");
}

public static void main(String[] args) {
    YieldTest yieldTest = new YieldTest();
    new Thread(yieldTest,"线程一").start();
    new Thread(yieldTest,"线程二").start();
}

join线程插队

@Override
public void run() {
    for (int i = 0; i < 100; i++) {
        System.out.println("VIP线程" + i);
    }
}

public static void main(String[] args) throws InterruptedException {
    Thread thread1 = new Thread(new JoinTest());
    thread1.start();

    //main线程
    for (int i = 0; i < 50; i++) {
        System.out.println("main线程" + i);
        if (i == 20) {
            //让thread1线程插队
            thread1.join(1);//传入插队时间,不传时间会一直执行该线程,直到执行完
        }
    }
}

State观察线程状态

getState() 观察线程状态

public static void main(String[] args) throws InterruptedException {
    Thread thread = new Thread(() -> {
        for (int i = 0; i < 5; i++) {
            System.out.println(i);
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    });

    //观察启动前 线程状态
    System.out.println(thread.getState()+"启动前-----------");

    thread.start();

    //观察启动后 线程状态
    Thread.State state = thread.getState();
    System.out.println(state+"----启动后");

    int i=1000;
    while(state!=Thread.State.TERMINATED){//判断线程是否终止
        System.out.println(++i);
        Thread.sleep(100);
        state = thread.getState();//更新线程状态
        System.out.println(state+"------------------while");
    }
}

Priority线程的优先级

最小的优先级为1,最大的为10,数字越大优先级越大
优先级只是增加cpu调度的概率

测试线程优先级

public static void main(String[] args) {
    //获得主线程的名字和优先级
    System.out.println(Thread.currentThread().getName()+"---"+Thread.currentThread().getPriority());

    PriorityTest priorityTest = new PriorityTest();
    Thread thread = new Thread(priorityTest);
    Thread thread1 = new Thread(priorityTest);
    Thread thread2 = new Thread(priorityTest);
    Thread thread3 = new Thread(priorityTest);
    //默认优先级
    thread.start();

    //先设置优先级在启动线程
    thread1.setPriority(1);
    thread1.start();

    thread3.setPriority(10);
    thread3.start();

    thread2.setPriority(3);
    thread2.start();
}

@Override
public void run() {
    //getPriority()取得当前线程的优先级
    System.out.println(Thread.currentThread().getName()+"---"+Thread.currentThread().getPriority());
}

Daemon守护线程

在这里插入图片描述

public class DaemonTest{
    public static void main(String[] args) {
        You you = new You();
        God god = new God();

        Thread thread = new Thread(god);
        /*
            setDaemon设置成守护线程;
            默认是false表示是用户线程,正常的线程都是用户线程,
                垃圾回收器:System.gc();是上帝线程
            用户线程结束后,守护线程会自动关闭
         */
        thread.setDaemon(true);
        //启动上帝守护线程
        thread.start();

        //启动用户线程
        new Thread(you).start();
    }
}

//上帝线程
class God implements Runnable{

    @Override
    public void run() {
        while(true){
            System.out.println("上帝线程");
        }
    }
}

//用户线程
class You implements Runnable{

    @Override
    public void run() {
        for (int i = 0; i < 360; i++) {
            System.out.println("用户线程");
        }
    }
}

synchronized同步块/同步方法

加了同步块之后多个线程会在方法的第一条语句等待

买票代码

//买票
class BuyTicket implements Runnable {
    //票数
    private int ticketNumber = 10;

    //标志位,用来终止线程
    boolean flag = true;

    @Override
    public void run() {
        //通过标志位来终止线程
        while (flag) {
            buy();
        }
    }

    //买票方法
    public synchronized void buy() {
        //判断是否还有票
        if (ticketNumber <= 0) {
            flag = false;
            //注意:这里一定要加return
            return;
        }
        try {
            Thread.sleep(200);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + "\t" + ticketNumber--);
    }
    
    public static void main(String[] args) {
        BuyTicket buyTicket = new BuyTicket();
        new Thread(buyTicket).start();
        new Thread(buyTicket).start();
        new Thread(buyTicket).start();
    }
}

银行取钱例子:

//银行取钱
public class UnsafeBank {
    public static void main(String[] args) {
        Account account = new Account(500, "安--");
        Bank bank = new Bank(account, 500);
        Bank bank1 = new Bank(account, 300);
        
        bank.start();
        bank1.start();
    }
}

//账户
class Account {
    //余额
    int money;
    //卡名
    String name;

    public Account(int money, String name) {
        this.money = money;
        this.name = name;
    }
}

//银行:模拟取款
class Bank extends Thread {
    //账户
    Account account;
    //取了多少钱
    int drawingMoney;
    //现在手里有多少钱
    int nowMoney;

    Bank(Account account, int drawingMoney) {
        this.account = account;
        this.drawingMoney = drawingMoney;
    }

    //取钱
    @Override
    public void run() {
        //操作谁同步块里就写谁
        synchronized (account) {
            //模拟延迟
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            //判断有没有钱
            if (account.money - drawingMoney < 0) {
                System.out.println(Thread.currentThread().getName() + "余额不足");
                return;
            }
            //取完钱后,卡内余额
            account.money = account.money - drawingMoney;
            //手里的钱
            nowMoney = nowMoney + drawingMoney;

            System.out.println(account.name + "余额为" + account.money);
            System.out.println(this.getName() + "手里的钱" + nowMoney);
        }
    }
}

死锁

Lock锁

synchronized与lock对比
在这里插入图片描述

public class LockTest implements Runnable {
    //票数
    private int ticketNumber = 10;

    //定义lock锁
    private final ReentrantLock lock = new ReentrantLock();

    @Override
    public void run() {
        while (true) {
            try {
                lock.lock(); //加锁
                if (ticketNumber > 0) {
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    ticketNumber--;
                    System.out.println(Thread.currentThread().getName() + "<--->" + ticketNumber);
                } else {
                    break;
                }
            } finally {
                lock.unlock(); //解锁
            }
        }
    }

    public static void main(String[] args) {
        LockTest lockTest = new LockTest();
        new Thread(lockTest).start();
        new Thread(lockTest).start();
        new Thread(lockTest).start();
    }
}

在这里插入图片描述

生产者和消费者

wait() 等待
notify 按照优先级唤醒一个,优先级相同随机唤醒一个
notifyAll() 唤醒全部
方法一:管程法
在这里插入图片描述
在这里插入图片描述

//测试生产者和消费者模型->利用缓冲区解决:管程法
public class PCTest {
    public static void main(String[] args) {
        SynContainer container = new SynContainer();
        new Productor(container).start();
        new Consumer(container).start();
    }
}

//生产者
class Productor extends Thread {
    SynContainer container;

    public Productor(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("生产了第"+i+"只鸡");
            container.push(new Chicken(i));
        }
    }
}

//消费者
class Consumer extends Thread {
    SynContainer container;

    public Consumer(SynContainer container) {
        this.container = container;
    }

    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            System.out.println("消费了第"+container.pop().id+"只鸡");
        }
    }
}

//产品
class Chicken {
    int id; //产品编号

    public Chicken(int id) {
        this.id = id;
    }
}

//缓冲区
class SynContainer {
    //定义容器
    Chicken[] chickens = new Chicken[10];
    //容器计数器
    int count = 0;

    //生产者放入产品
    public synchronized void push(Chicken chicken) {
        //如果容器满了,就需要等待消费者消费
        if (count == chickens.length) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            //通知消费者消费,生产等待
        }
        //如果没有满,我们就需要丢入产品
        chickens[count] = chicken;
        count++;

        //可以通知消费者消费了
        this.notifyAll();
    }

    //消费者消费产品
    public synchronized Chicken pop() {
        //判断能否消费
        if (count == 0) {
            //等待生产者生产
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        //如果可以消费
        count--;
        Chicken chicken = chickens[count];
        //通知生产者生产
        this.notifyAll();
        return chicken;
    }
}

方法二:信号灯法

//测试生产者和消费者问题2:信号灯法,标志位解决
public class PCTest2 {
    public static void main(String[] args) {
        TV tv = new TV();
        new Player(tv).start();
        new Watcher(tv).start();
    }
}

//生产者->演员
class Player extends Thread {
    TV tv;
    public Player(TV tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            if (i%2==0){
                this.tv.play("快乐大本营");
            }else{
                this.tv.play("王牌对王牌");
            }
        }
    }
}

//消费者->观众
class Watcher extends Thread {
    TV tv;
    public Watcher(TV tv){
        this.tv=tv;
    }

    @Override
    public void run() {
        for (int i = 0; i < 10; i++) {
            tv.watch();
        }
    }
}

//产品->节目
class TV {
    //演员表演,观众等待
    //观众观看,演员等待

    String voice;//表演的节目

    //标志位,true时演员表演,false是观众观看
    boolean flag = true;

    //表演
    public synchronized void play(String voice){
        if (!flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("演员表演了"+voice);

        //赋值要观看的节目
        this.voice=voice;
        //通知观众观看
        this.notifyAll();//唤醒观众
        this.flag=!this.flag;
    }

    //观看
    public synchronized void watch(){
        if (flag){
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println("观看了"+voice);
        //通知演员表演
        this.notifyAll();
        this.flag=!this.flag;
    }
}

线程池

在这里插入图片描述

静态代理案例:

/**
 * 静态代理模式总结:
 * 真是对象和代理对象都要实现同一个接口
 * 代理对象要代理真是对象
 */

public class StaticProxy {
    public static void main(String[] args) {
        Marry weddingCompany = new WeddingCompany(new You());
        weddingCompany.happyMarry();
    }
}

//结婚接口
interface Marry {
    void happyMarry();
}

//真实对象
class You implements Marry {

    @Override
    public void happyMarry() {
        System.out.println("我结婚了");
    }
}

//代理对象
class WeddingCompany implements Marry {

    //传入真实对象
    private Marry target;

    public WeddingCompany(Marry target) {
        this.target = target;
    }

    @Override
    public void happyMarry() {
        before();//代理
        target.happyMarry();//真实对象
        after();//代理

    }

    private void before() {
        System.out.println("结婚之前,布置现场");
    }

    private void after() {
        System.out.println("结婚之后,收尾款");
    }
}

Lambda表达式

使用lambda前提是接口需要是函数式接口(有且仅有一个方法)

实现函数式接口的五种方法

public class Lambda {
    //方法二:内部类或静态内部类
    static class Like2 implements ILike {
        @Override
        public void lambda() {
            System.out.println("内部类或静态内部类实现函数式接口");
        }
    }

    public static void main(String[] args) {
        //方法三:局部内部类
        class Like3 implements ILike {
            @Override
            public void lambda() {
                System.out.println("局部内部类实现函数式接口");
            }
        }

        //方法四:匿名内部类
        ILike like4 = new ILike() {
            @Override
            public void lambda() {
                System.out.println("匿名内部类实现函数式接口");
            }
        };
        //方法五:用lambda表达式(简化匿名内部类操作)
        ILike like5 = () -> {
            System.out.println("用lambda表达式实现函数式接口");
        };

        /*=========================测试=========================*/
        //调用实现类
        new Like().lambda();
        //调用内部类或静态内部类
        new Like2().lambda();
        //调用局部内部类
        new Like3().lambda();
        //调用匿名内部类
        like4.lambda();
        //调用lambda表达式
        like5.lambda();
        /*=====================================================*/
    }
}


//1.定义一个函数式接口
interface ILike {
    public void lambda();
}

//2.实现接口方法一:实现类
class Like implements ILike {
    @Override
    public void lambda() {
        System.out.println("实现类实现函数式接口");
    }
}

简化lambda表达式

public class Lambda {
    public static void main(String[] args) {
        //匿名内部类
        ILike like = new ILike() {
            @Override
            public String lambda(int a) {
                return a + "--like";
            }
        };
        System.out.println(like.lambda(0));

        //1.简化成lambda表达式
        ILike like1 = (int a) -> {
            return a + "--like1";
        };
        System.out.println(like1.lambda(1));

        //2.简化参数类型
        ILike like2 = (a) -> {
            return a + "--like2";
        };
        System.out.println(like2.lambda(2));

        //3.简化括号 //前提只有一个参数
        ILike like3 = a -> {
            return a + "--like2";
        };
        System.out.println(like3.lambda(3));

        //4.简化花括号   //前提只有一行代码
        ILike like4 = a -> a + "--like2";
        System.out.println(like4.lambda(4));
    }
}

//1.定义一个函数式接口
interface ILike {
    public String lambda(int a);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值