class 和 数组 在内存上的相似性

类和数组的 名 ,均保存的是地址值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public static class myclass()
{
int num;
string str;

public void change(int a ,string s)
{
a = a+1;
}
}
...mian...()
{
myclass class01 = new myclass();
myclass class02 = class01;//这一步把class01的地址值赋值给了class02,他们两个现在指向同一片内存空间
}
成员变量和局部变量的区别
  • 初始化值不同:

    成员变量有初始值,局部变量没有

  • 内存位置不同:

    成员变量在堆中(本质是跟着对象走),局部变量在栈中(本质是跟着方法走)

  • 生命周期不同:

    成员变量跟着对象走,随着对象的产生而产生,随着对象的消亡而消亡

    局部变量跟着方法走,随着方法的调用而产生,随着方法结束而消亡

this关键字——>区分成员变量和局部变量
  • 局部变量和成员变量重名时,遵循“就近原则”
  • 如果就想用成员变量,那就用 this.变量名 来引用成员变量

对象之间如何区分?

  • 哪个对象调用的方法,this就指向哪个对象
引用数据类型,要先new

(什么是引用数据类型:除了基本数据类型,都是引用数据类型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public static class MyData()
{
int a;
string s;
static float c;
}

//========== 其他作用域=========

string a = "666"; //正常赋值
int c = string b.length; //报错,空指针,根本原因是没有初始化string类型具体是什么,而直接操作他的成员变量

//同理:

MyData mydata = new MyData();
mydata.a = 1; //正常,先new了一个对象,然后操作他的成员变量

MyData mydata_error.a = 2; //空指针,因为连mydata_error对象都还没创建,就直接操作他的成员变量


//但是,static的变量可以直接通过 类名 访问,(不是对象名)

MyData.c = "我是静态变量"; //正常

javabean在业务处理中的作用

javabean与表的对应关系

类名——>表名

各个实例化对象——>每一行

成员变量——>每一列的列头(也就是对应的参数)

  • 添加功能:

image-20250403200744494

  • 查询功能:
    image-20250403201600516

标准javabean生成快捷键:alt + insert

java中,static的用法

静态成员随着类的调用而产生,非静态成员随着对象的产生而产生

因此注意四种辨析:

  • 在静态成员中能直接访问非静态成员吗:

    不能,想在静态成员中访问非静态成员,要先new对象
    eg:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class Demo{
    public static void main(String[] args){
    test01(); //——————>可行,静态调用静态
    test02(); //——————>不可行,静态不能直接调用非静态,因为静态成员比非静态先产生

    //===正确调用:========
    Demo mydemo = new Demo();
    mydemo.test02();
    //====================
    }
    public static void test01(){
    sout("我是静态成员");
    }
    public void test02(){
    sout("我是非静态成员");
    }
    }

  • 在非静态方法中能直接访问静态成员吗:

    可以,同类下的话,直接调用即可,不同类的话,通过类名调用(也就是静态方法跟着类走,不跟着对象走)

    当然,也可以不管是不是同类,直接类名调用

  • 在静态方法中能直接调用静态成员吗:

    可以,同上

  • 在非静态方法中能直接调用非静态成员吗?

    可以,同类下可以直接调用,也可以new对象调用,不同类下需要new对象调用

    当然,也可以不管是否同类,都通过new对象调用

总结:

1.不管在不在同一个类中,非静态成员都可以new对象调用

2.不管在不在同一个类中,静态成员都可以类名调用

可变参数

可变参数本质上是一个数组,用于传递类型已知但数量未知的数据类型

形式:

数据类型…变量名,如 int…nums String…kids

还有,可变参数必须位于传参的最后面位置

对象数组

就是数组的元素是对象,类如

int数组:int[] arr_int = new int[3]

Person数组: Person arr_person = new Person[3]

一些操作
  • 先调用方法再生成:

    alt+回车

  • 将一段代码抽取到一个方法:

    ctrl+alt+m

有关继承:
子类可以继承什么

a.子类可以继承父类中私有和非私有成员,但是不能使用父类中私有成员

b.构造方法不能继承

成员变量和成员方法各自的访问特点(同样适用于多态)
  • 成员变量:看等号左边,左边是谁就用谁的成员变量,比如如果等号左边是子类,且没有,再去找父类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class fu {
    int num;
    }

    public class zi extends fu{
    int num; //也叫num,两者重名
    }
    public static void main(String args[]){
    fu fu_ = new fu();
    zi zi_ = new zi();

    /*
    sout(fu.num) ——>父类的num
    sout(zi.num) ——>子类的num
    */

    //多态:
    fu fu_2 = new zi();
    // sout(fu_2.num) ——>子类的num,因为继承中的成员变量看等号左边

    }
  • 成员方法:与成员变量相反,他看等号右边new的是谁,不做展示

方法的重写
1
2
3
4
5
1.概述:子类中有一个和父类方法名以及参数列表相同的方法
2.前提:继承
3.访问:看new的是谁,先调用谁中的,如果new的是子类,调用调用子类重写的方法,子类没有,找父类
4.检测是否为重写方法:在该方法上写
@Override

注意事项:

1
2
3
4
5
6
1.子类重写父类方法之后,权限必须要保证大于等于父类权限(权限指的是访问权限)
public -> protected -> 默认 -> private
2.子类方法重写父类方法,方法名和参数列表要一样 //和重载要求参数列表不同不一样,这个要求一样
3.私有方法不能被重写,构造方法不能被重写,静态方法不能被重写
4.子类重写父类方法之后,返回值类型应该是父类方法返回值类型的子类类型 //意思就是,子类的返回值如果是一个类的话,那这个类必须是父类返回值的那个类的子类

super和this
1
2
3
4
1.注意:new子类对象时,会先初始化父类(先走父类无参构造方法)
2.原因:
每个构造方法的第一行,默认都会有一个super(),不写jvm自动提供一个
super()代表的是父类无参构造

也就是说,子必有父,调用子类,如果不 显示使用super(有参)的话 父类一定会默认走一次无参构造

super的使用:

1
2
3
4
5
6
7
8
9
10
11
12
1.概述:代表的是父类引用
2.作用:可以调用父类中的成员
3.使用:
a.调用父类构造方法-> 在子类中的构造中写
super() -> 调用父类无参构造
super(实参) -> 调用父类有参构造

b.调用父类成员变量:
super.成员变量名

c.调用父类成员方法:
super.成员方法名(实参)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
1.this概述:代表的是当前对象(哪个对象调用的this所在的方法,this就代表哪个对象)
2.作用:
a.区分重名的成员变量和局部变量
b.调用当前对象中的成员
3.使用:
a.调用当前对象的构造:在构造中写
this():调用当前对象的无参构造
this(实参):调用当前对象的有参构造
b.调用当前对象的成员变量:
this.成员变量名
c.调用当前对象的成员方法:
this.成员方法名(实参)
4.注意:
不管是super还是this,只要在构造中使用,都必须在第一行,所以二者不能同时手写出来

super 和 this 不能同时出现,因为两个都要在第一行

继承的特点:

只能单继承,不能多继承

想给private赋值或读取,那就要用到非私有的方法,getset也好,构造方法也行

抽象:

image-20250411215743850

抽象的真正意义:

  • 可以将抽象类看成是一类事物的标准,要求只要是属于这一类的,都必须要拥有抽象类中的方法,必须要给我实现
  • 怎么证明拥有了,怎么证明实现了呢?-> 重写
接口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
1.接口:是一个引用数据类型,是一种标准,规则
2.关键字:
a.interface 接口
public interface 接口名{}

b.implements 实现
实现类 implements 接口名{}

3.接口中可以定义的成员:

a.jdk7以及之前:
抽象方法: public abstract -> 即使不写public abstract,默认也有
成员变量:public static final 数据类型 变量名 = 值-> 即使不写public static final,默认也有
final是最终的,被final修饰的变量不能二次赋值,所以我们一般将final修饰的变量视为常量

b.jdk8:
默认方法:public default 返回值类型 方法名(形参){}
静态方法:public static 返回值类型 方法名(形参){}

c.jdk9开始:
私有方法:
private的方法
接口中的抽象方法:
1
2
3
4
5
6
7
8
1.定义格式:
public abstract 返回值类型 方法名(形参);
2.注意:
不写public abstract 默认也有
3.使用:
a.定义实现类,实现接口
b.重写抽象方法
c.创建实现类对象,调用重写的方法
接口中的默认方法:(要显示default)
1
2
3
4
5
6
7
8
9
1.格式:
public default 返回值类型 方法名(形参){
方法体
return 结果
}
2.使用:
a.定义实现类,实现接口
b.默认方法可重写,可不重写
c.创建实现类对象,调用默认方法

接口中的静态方法:

1
2
3
4
5
6
7
8
1.定义格式:
public static 返回值类型 方法名(形参){
方法体
return 结果
}

2.使用:
接口名直接调用

默认方法和静态方法的作用:默认方法和静态方法 -> 可以作为临时加的一个小功能来使用

接口中的成员变量
1
2
3
4
5
6
7
8
9
10
11
1.格式:
public static final 数据类型 变量名 = 值
2.相关知识点:final
final代表最终的,被它修饰的变量,不能二次赋值,可以视为常量
3.特点:
不写public static final 默认也有
4.使用:
接口名直接调用
5.注意:
a.被static final修饰的成员变量需要手动赋值
b.习惯上我们会将static final修饰的成员变量名大写
总结一下接口的成员变量和成员方法

继承也好,实现接口也罢,只要是父类中或者接口的抽象方法,子类或者实现类都要重写

接口中的成员变量:public static final,直接通过接口名调用

接口中的静态方法:public static method(),直接通过接口名调用

接口中的 默认方法 和 抽象方法:不写前缀默认是抽象方法,显式public default,是默认方法,二者,抽象方法必须在实现类中重写,然后通过new实现类来调用,default方法可重现可不重写,但也要通过new实现类来调用

注意,多个接口中的抽象方法或默认方法重名,实现类都要重写一次抽象方法或默认方法

接口和抽象类的区别:
1
2
3
4
5
6
7
8
9
相同点:
a.都位于继承体系的顶端,用于被其他类实现或者继承
b.都不能new
c.都包含抽象方法,其子类或者实现类都必须重写这些抽象方法

不同点:
a.抽象类:一般作为父类使用,可以有成员变量,构造,成员方法,抽象方法等
b.接口:成员单一,一般抽取接口,抽取的都是方法,视为功能的大集合
c.类不能多继承,但是接口可以
多态
多态的表达方式:

Fu fu = new Zi();

也就是:父类引用指向子类对象

多态的相关使用说明:

  • 父类引用指向子类对象后,这个引用不能调用子类的特有功能(也就是不是重写的父类中的功能),这是一个弊端

  • 由于多态是父类引用指向子类对象,相当于 一个大的数据类型接受了一个小的数据类型的赋值 ,如 double x = 10,因此,它具有很强的 兼容性 ,他能够兼容比自己小的数据类型传来的赋值,也就是说,这个Fu fu 可以随便被自己的子类给赋值,无论是new zi1(); 还是 new zi2();

    因此,多态常用于执行方法的形参中

  • 多态下,成员变量和成员方法的访问特点:成员变量看左边,一般是父类的,成员方法看右边,一般是子类的,还有就是多态一般是用来玩方法的,因此大多都只用成员方法即可

多态中的向下转型:

类似于强转,将大类型强制转换成小类型

1
2
3
4
5
6
7
8
9
10
11
12
//例如,Animal animal是父类,Dog dog是子类

//转型语句:
Dog dog = (Dog) animal;

//但是注意,向下转型以后,原来的方法中可能会存在类型转换异常,原因是,一个方法中如果集合了很多子类的特有方法,转成一种以后,就会和其他的子类方法起冲突
//解决办法: 对象名 instanceof 类型 -> 判断的是关键字前面的对象是否符合关键字后面的类型
if (animal instanceof Cat){
Cat cat = (Cat) animal;
cat.eat();
cat.catchMouse();
}
权限修饰符

image-20250418191139231

final关键字
final关键字可以修饰的内容:

类:不能被继承

方法:不能被重写

局部变量:值不能被改变

成员变量:需要手动赋值,且不能二次赋值

对象:对象的属性值可以改变,但是对象的地址值不能改变

代码块:

构造代码块:执行特点:优先于构造方法执行,每new一次,就会执行一次

静态代码块:执行特点:优于构造方法和构造代码块执行,且只执行一次

如果想让一些数据最先初始化,而且只需要初始化一次,就可以将这些数据放到静态代码块中

比如初始化数据库的过程中,每次都要注册驱动,初始化操作数据库的地址,用户名,密码啥的,是没有意义的,因此放到一个静态代码块中只初始化一次即可

内部类

内部类的分类:

成员内部类:

  • 静态内部类
  • 非静态内部类

局部内部类

匿名内部类

静态内部类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1.格式:直接在定义内部类的时候加上static关键字
public class A{
static class B{

}
}

2.注意:
a.内部类可以定义属性,方法,构造等
b.静态内部类可以被final或者abstract修饰
final修饰之后,不能被继承
abstract修饰之后,不能new
c.静态内部类不能调用外部的非静态成员
d.内部类还可以被四种权限修饰符修饰

3.调用静态内部类成员:
外部类.内部类 对象名 = new 外部类.内部类()
非静态内部类:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1.格式:直接在定义内部类的时候加上static关键字
public class A{
class B{

}
}

2.注意:
a.内部类可以定义属性,方法,构造等
b.静态内部类可以被final或者abstract修饰
final修饰之后,不能被继承
abstract修饰之后,不能new
c.静态内部类不能调用外部的非静态成员
d.内部类还可以被四种权限修饰符修饰

3.调用非静态内部类成员:
外部类.内部类 对象名 = new 外部类().new 内部类()

外部类与内部类的成员变量以及内部类的局部变量重名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Student {
String name = "金莲";
class Heart{
String name = "大郎";
public void display(String name){
System.out.println(name);//内部类的局部变量
System.out.println(this.name);//内部类的成员变量
System.out.println(Student.this.name);//外部类的成员变量
}
}
}


public class Test02 {
public static void main(String[] args) {
Student.Heart heart = new Student().new Heart();
heart.display("涛哥");
}
}

在内部类中,变量前没有任何修饰,是局部变量

有 this. 修饰,是内部成员变量

外部类名.this. 修饰,是外部类的成员变量

8_15更新

API
String

所有字符串类型的的“变量”,常量,都是String的实现类对象

字符串类型本质上是常量,一旦创建就不能改变,对字符串修改的过程实际上是创建新对象的过程

字符串对象是不可变的,所以可以共享,已经定义了一个s1,如果s2和s1内容一样,那么定义s2就会复用s1

实现原理

String的实现原理分为jdk8之前和之后

之前: private final char[] value

之后: private final bytes[] value

由char变成bytes,内存占用从2个字节到1个字节 ——>节省内存

String面试题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class Demo04String {
public static void main(String[] args) {
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
System.out.println(s1==s2);//true
System.out.println(s1==s3);//false
System.out.println(s2==s3);//false
}
}

字符串常量池可以避免重复创建相同字符串
==比较的是对象引用地址,不是内容
new String()总是创建新对象,即使内容相同
如果要比较内容,应该使用equals()方法而不是==


public class Demo05String {
public static void main(String[] args) {
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";
String s4 = "hello"+"world";
String s5 = s1+"world";
String s6 = s1+s2;

System.out.println(s3==s4);//true
System.out.println(s3==s5);//false
System.out.println(s3==s6);//false
}
}

1.字符串拼接,如果等号右边是字符串字面值拼接,不会产生新对象

2.字符串拼接,如果等号右边有变量参数拼接,会产生新字符串对象

String 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
boolean equals(String s) -> 比较字符串内容
boolean equalsIgnoreCase(String s) -> 比较字符串内容,忽略大小写

int length()
String concat(String s) 字符串拼接,返回新串
char charAt(int index) 获取对应的字符
int indexOf (String s) 返回第一次s字串在大串中出现的索引位置
String subString (int beginIdex) 截取字符串 从指定的所用开始
String subString (int begin,int end) 截取字符串,含头不含尾


char[] toCharArray() 将字符串转成char数组
byte[] getBytes() 将字符串转成byte数组
byte[] getBytes(String charsetname) 根据给定的编码格式转换

String[] split (String regex) regex是正则表达式

boolean contains(String s) -> 判断老串儿中是否包含指定的串儿
boolean endsWith(String s) -> 判断老串儿是否以指定的串儿结尾
boolean startsWith(String s) -> 判断老串儿是否以指定的串儿开头
String toLowerCase()-> 将字母转成小写
String toUpperCase() -> 将字母转成大写
String trim() -> 去掉字符串两端空格

StringBulider

StringBulider 是可变的,相比于String的不可变,每次操作都要新建对象,StringBulider可以直接修改

StringBulider方法:

1
2
3
StringBulider append(任意类型的数据) 字符串拼接,返回的是StringBulider自己
StringBulider reverse() 字符串反转,返回的是StringBulider自己
String toString() 返回将自己转为String类型后的字符串

StringBulider vs StringBuffer

builder效率高,线程不安全,buffer比builder慢,线程安全

其他api

Math工具类

1
2
3
4
5
6
static int abs(int a) -> 求参数的绝对值
static double ceil(double a) -> 向上取整
static double floor(double a) ->向下取整
static long round(double a) -> 四舍五入
static int max(int a, int b) ->求两个数之间的较大值
static int min(int a, int b) ->求两个数之间的较小值

BigInteger大数 BigDecimal大小数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
构造:
BigInteger(String val) -> 参数的格式必须是数字形式
方法:
BigInteger add(BigInteger val) 返回其值为 (this + val) 的 BigInteger
BigInteger subtract(BigInteger val) 返回其值为 (this - val) 的 BigInteger
BigInteger multiply(BigInteger val) 返回其值为 (this * val) 的 BigInteger
BigInteger divide(BigInteger val) 返回其值为 (this / val) 的 BigInteger


构造方法:
BigDecimal(String val) -> val必须要是数字形式

常用方法:
static BigDecimal valueOf(double val) -> 此方法初始化小数时可以传入double型数据
BigDecimal add(BigDecimal val) 返回其值为 (this + val) 的 BigDecimal
BigDecimal subtract(BigDecimal val) 返回其值为 (this - val) 的 BigDecimal
BigDecimal multiply(BigDecimal val) 返回其值为 (this * val) 的 BigDecimal
BigDecimal divide(BigDecimal val) 返回其值为 (this / val) 的 BigDecimal
BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
divisor:除号后面的那个数
scale:指定保留几位小数
roundingMode:取舍方式
static int ROUND_UP -> 向上加1
static int ROUND_DOWN -> 直接舍去
static int ROUND_HALF_UP -> 四舍五入

Date 日期类

1
2
3
4
5
6
1.构造:
Date() -> 获取当前系统时间
Date(long time) -> 获取指定时间,传递毫秒值 -> 从时间原点开始算 比如传递1000l,就是原点后1

2.方法:
setTime和getTime

Calendar 日历类

image-20250815080312300

1
2
3
4
5
6
7
常用方法:
int get(int field) ->返回给定日历字段的值
void set(int field, int value) :将给定的日历字段设置为指定的值
void add(int field, int amount) :根据日历的规则,为给定的日历字段添加或者减去指定的时间量
Date getTime():将Calendar转成Date对象

void set(int year, int month, int date) -> 直接设置年月日

SimpleDateFormat日期格式化类

1
2
3
4
5
6
7
8
9
10
11
1.概述:日期格式化类
2.构造:
SimpleDateFormat(String pattern)
3.pattern代表啥:代表的是我们自己指定的日期格式
字母不能改变,但是中间的连接符我们可以改变

yyyy-MM-dd HH:mm:ss

常用方法:
1.String format(Date date) -> 将Date对象按照指定的格式转成String
2.Date parse(String source)-> 将符合日期格式的字符串转成Date对象

JDK8新日期类

LocalDate LocalDateTime对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
1.概述:LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日
2.获取:
static LocalDate now() -> 创建LocalDate对象
static LocalDate of(int year, int month, int dayOfMonth) -> 创建LocalDate对象,设置年月日



1.LocalDateTime概述:LocalDateTime是一个不可变的日期时间对象,代表日期时间,通常被视为年 - 月 - 日 - 时 - 分 - 秒。
2.获取:
static LocalDateTime now() 创建LocalDateTime对象
static LocalDateTime of(int year, Month month, int dayOfMonth, int hour, int minute, int second) 创建LocalDateTime对象,设置年月日时分秒


从LocalDate 和 LocalDateTime中获取指定字段的方法:
int getYear()->获取年份
int getMonthValue()->获取月份
int getDayOfMonth()->获取月中的第几天
设置各个字段的方法:
LocalDate withYear(int year):设置年份
LocalDate withMonth(int month):设置月份
LocalDate withDayOfMonth(int day):设置月中的天数

日期字段偏移(用新的对象去接收):
设置日期字段的偏移量,方法名plus开头,向后偏移
设置日期字段的偏移量,方法名minus开头,向前偏移
eg: LocalDate myLD = new LocalDate();
想要在这个ld对象的基础上,往前偏移一年,就调用方法minusYears:
LocalDate myMinusLD = myLD.minusYears(1L);

Period和Duration类

这两者都是计算时间差的,period操作的是LocalDate对象,年月日分别计算,Duration操作的是LocalDate 和LocalDateTime对象,是获取总天/时/分/秒差值的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
static Period between(LocalDate d1,LocalDate d2):计算两个日期之间的差值

getYears()->获取相差的年
getMonths()->获取相差的月
getDays()->获取相差的天



static Duration between(Temporal startInclusive, Temporal endExclusive) -> 计算时间差
Temporal : 是一个接口
实现类:LocalDate LocalDateTime

参数需要传递 Temporal 的实现类对象, 注意要传递LocalDateTime
因为Duration计算精确时间偏差,所以需要传递能操作精确时间的 LocalDateTime


利用Dutation获取相差的时分秒 -> to开头
toDays() :获取相差天数
toHours(): 获取相差小时
toMinutes():获取相差分钟
toMillis():获取相差秒(毫秒)

DateTimeFormatter日期格式化类

1
2
3
4
5
6
7
8
9
10
1.获取:
static DateTimeFormatter ofPattern(String pattern) -> 获取对象,指定格式
2.方法:
String format(TemporalAccessor temporal)-> 将日期对象按照指定的规则转成String
TemporalAccessor:接口,子接口有Temporal
Temporal的实现类:LocalDate LocalDateTime

TemporalAccessor parse(CharSequence text)-> 将符合规则的字符串转成日期对象
如果想将TemporalAccessor转成我们常见的LocalDateTime日期对象,就需要用到LocalDateTime中的静态方法:
static LocalDateTime from(TemporalAccessor temporal)

System类:

image-20250815082633405

Arrays工具类:

image-20250815082817290

Callable与线程池

image-20250815084012847

使用方法:

1.自定义类实现callabe接口,重写call方法,其中call方法的返回值就是callable接口应用时指定的泛型

2.创建线程池对象,将自定义类new的对象submit到线程池中,并用future对象接收submit方法的返回值

3.对future对象执行get方法,可以获得call方法的返回值

线程池
原生创建线程池的方式

image-20250815215632996

image-20250815215653650

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
//自定义一个线程工厂对象,重写newThread方法,可以自行对线程进行一些设置
public class myThreadFactory implements ThreadFactory{
private final AtomicInteger i = new AtomicInteger(1); //创建原子计数器,这东西操作是原子性的,线程安全
@Override
public Thread newThread(Runnable r){
Thread thread = new Thread(r);
Thread.setName("线程"+i.getAndIncrement()+"号");
return thread;
}
}


//编写一个任务,通过自定义类实现runnable接口实现
public class Task implements Runnable{
@Override
public void run(){
System.out.plintln(Thread.currentThread().getName());
}
}

//在main方法中使用线程池
public static void main(String[] args){
//创建三个任务
Task task1 = new Task();
Task task2 = new Task();
Task task3 = new Task();

//创建线程池对象
ThreadPoolExecutor mytpe = new ThreadPoolExecutor(10,25,10L,
TimeUnit.SECONDS,
new LinkdBlockingQueue<>(),
new myThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
mytpe.execute(task1);
mytpe.execute(task2);
mytpe.execute(task3);

//关闭线程池
mytpe.shutdown();
}

各个参数详解:

10:核心线程数量

25:最大线程数量

10L:空闲线程存活时间

new LinkdBlockingQueue<>():任务队列,这里使用阻塞链式队列,还有阻塞数组队列

new myThreadFactory():线程工厂

new ThreadPoolExecutor.AbortPolicy():拒绝任务策略,这里是默认的策略

三种不推荐的创建线程池的方式:

image-20250815221805670

image-20250815221914018

原因就是他们的任务队列存在溢出风险

提交任务的两种方式,execute和submit

image-20250815222203241

image-20250815222219082

future对象中的get方法:

future对象中的get方法作用是获取call的return的结果

默认是阻塞的

如果想给这个get设定一个超时时间,就在get里面传入参数即可,如 future.get(1, TimeUnit.SECONDS);

image-20250815222601775

future对象中的cancel方法:

image-20250815222656651

未执行的任务,调用cancel方法,传递的参数true和false是没有作用的,因为根本用不到,结果是能取消任务

正在执行中的任务,

​ 1.传递true代表可以相应中断线程指令(相当于打开了中断线程指令的获取权),这时候程序可以根据中断线程指令来做出相应行为(如果不手动根据指令做出动作,那和false没区别)

​ 2.传递false,代表没有什么使用权,当前任务会继续执行完

已完成的任务,无法取消

quastion:既然false的时候,程序还是执行完了,那标记有啥意义?

答:仅作逻辑标记

任务拒绝策略:

image-20250815224437313

shutdown&&shutdownNow方法:

image-20250815224705096

image-20250815225022596

线程池状态

image-20250815225301231

image-20250815225310827

线程池执行流程

image-20250815233301354

线程池批量执行

image-20250815234043731

集合

image-20250815234851152

image-20250815234950023

IO流
File类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
1.两个操作符常量:
static String pathSeparator:与系统有关的路径分隔符,为了方便,它被表示为一个字符串。
static String separator:与系统有关的默认名称分隔符,为了方便,它被表示为一个字符串。


2.File的构造方法:
File(String parent, String child) 根据所填写的路径创建File对象
parent:父路径
child:子路径
File(File parent, String child) 根据所填写的路径创建File对象
parent:父路径,是一个File对象
child:子路径
File(String pathname) 根据所填写的路径创建File对象
pathname:直接指定路径


3.File的获取方法:
String getAbsolutePath() -> 获取File的绝对路径->带盘符的路径
String getPath() ->获取的是封装路径->new File对象的时候写的啥路径,获取的就是啥路径
String getName() -> 获取的是文件或者文件夹名称
long length() -> 获取的是文件的长度 -> 文件的字节数


4.File的创建/删除方法:
boolean createNewFile() -> 创建文件
如果要创建的文件之前有,创建失败,返回false
如果要创建的文件之前没有,创建成功,返回true

boolean mkdirs() -> 创建文件夹(目录)既可以创建多级文件夹,还可以创建单级文件夹
如果要创建的文件夹之前有,创建失败,返回false
如果要创建的文件夹之前没有,创建成功,返回true

boolean delete()->删除文件或者文件夹
注意:
1.如果删除文件,不走回收站
2.如果删除文件夹,必须是空文件夹,而且也不走回收站


5.File的判断方法
boolean isDirectory() -> 判断是否为文件夹
boolean isFile() -> 判断是否为文件
boolean exists() -> 判断文件或者文件夹是否存在


6.File的遍历方法
String[] list() -> 遍历指定的文件夹,返回的是String数组
File[] listFiles()-> 遍历指定的文件夹,返回的是File数组 ->这个推荐使用

细节:listFiles方法底层还是list方法
调用list方法,遍历文件夹,返回一个Stirng数组,遍历数组,将数组中的内容一个一个封装到File对象中,然后再将File对象放到File数组中

字节字符流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
字节流:万能流,一切皆字节
字节输出流: OutputStream 抽象类
字节输入流: InputStream 抽象类

字符流:专门操作文本文档
字符输出流:Writer 抽象类
字符输入流:Reader 抽象类

1.OutputStream:
构造(使用的是实现类FileOutputStream):
FileOutputStream(File file)
FileOutputStream(String name)

特点:
a.指定的文件如果没有,输出流会自动创建
b.每执行一次,默认都会创建一个新的文件,覆盖老文件

方法:
void write(int b) 一次写一个字节
void write(byte[] b) 一次写一个字节数组
void write(byte[] b, int off, int len) 一次写一个字节数组一部分
b:写的数组
off:从数组的哪个索引开始写
len:写多少个
void close() -> 关闭资源

字节流的续写追加:
FileOutputStream(String name, boolean append)
append:true -> 会实现续写追加,文件不覆盖了



2.InputStream
构造:(使用的是实现类FileInputStream)
FileInputStream(File file)
FileInputStream(String path)

方法:
int read() 一次读一个字节,返回的是读取的字节
int read(byte[] b) 一次读取一个字节数组,返回的是读取的字节个数
int read(byte[] b, int off, int len) 一次读取一个字节数组一部分,返回的是读取的字节个数
void close() 关闭资源


3.FileWriter
构造:
FileWriter(File file)
FileWriter(String fileName)
FileWriter(String fileName, boolean append) -> 追加,续写
方法:
void write(int c) -> 一次写一个字符
void write(char[] cbuf) 一次写一个字符数组
void write(char[] cbuf, int off, int len) 一次写一个字符数组一部分
void write(String str) 直接写一个字符串
void flush() :将缓冲区中的数据刷到文件中
void close() 关流 (调用时,自动触发flush)
注意:FileWriterr底层自带一个缓冲区,我们写的数据会先保存到缓冲区中,所以我们需要将缓冲区中的数据刷到文件中
flush():将缓冲区中的数据刷到文件中,后续流对象还能继续使用
close():先刷新后关闭,后续流对象不能使用了



4.FileReader
构造:
FileReader(File file)
FileReader(String path)
方法:
int read() -> 一次读取一个字符,返回的是读取字符对应的int
int read(char[] cbuf) -> 一次读取一个字符数组,返回的是读取个数
int read(char[] cbuf, int off, int len) -> 一次读取一个字符数组一部分,返回的是读取个数
cbuf:读取的数组
off:从数组的哪个索引开始读
len:读多少个
void close() -> 关闭资源


5.JDK7之后io异常处理方式
1.格式:
try(IO对象){
可能出现异常的代码
}catch(异常类型 对象名){
处理异常
}
2.注意:
以上格式处理IO异常,会自动关流
字节/字符缓冲流 转换流 序列化接口/序列化流 打印流
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
//字节缓冲流
a.BufferedOutputStream:字节缓冲输出流
构造:BufferedOutputStream(OutputStream out)
使用:和FileOutputStream一样

b.BufferedInputStream:字节缓冲输入流
构造:BufferedInputStream(InputStream in)
使用:和FileInputStream一样


//字符缓冲输出流_BufferedWriter
构造:
BufferedWriter(Writer w)
方法:
用起来和FileWriter一样
特有方法:
newLine() 换行

//字符缓冲输入流_BufferedReader
构造:
BufferedReader(Reader r)
方法:
用法和FileReader一样
特有方法:
String readLine()-> 一次读一行,如果读到结束标记,返回的是null


//转换流_InputStreamReader
构造:
InputStreamReader(InputStream in,String charsetName)
charsetName:指定编码,不区分大小写
作用:
可以直接指定编码,按照指定的编码去读内容
用法:
基本用法和FileReader一样


//转换流_OutputStreamWriter
构造:
OutputStreamWriter(OutputStream out,String charsetName)
作用:
按照指定的编码规则去存数据
用法:
和FileWriter一样


//序列化流和反序列化流
ObjectOutputStream -> 序列化流 -> 写对象
ObjectInputStream -> 反序列化流 -> 读对象

序列化eg:
private static void write()throws Exception {
ObjectOutputStream oos =
new ObjectOutputStream(new FileOutputStream("module22\\person.txt"));
Person p1 = new Person("涛哥", 12);
oos.writeObject(p1);
oos.close();
}
反序列化eg:
private static void read()throws Exception {
ObjectInputStream ois =
new ObjectInputStream(new FileInputStream("module22\\person.txt"));
Person person = (Person) ois.readObject();
System.out.println(person);
ois.close();
}

打印流eg:
public class Demo01PrintStream {
public static void main(String[] args)throws Exception{
PrintStream ps = new PrintStream("module22\\printstream.txt");
ps.println("涛哥是一个大帅哥");
ps.println("涛哥是一个小鲜肉");
ps.println("涛哥和金莲不为人知的故事");
ps.close();
}
}
改变流向:
什么叫做改变流向:
System.out.println()-> 本身是输出到控制台上
改变流向:可以让输出语句从控制台上输出改变成往指定文件中输出

方法:System中的方法:
static void setOut(PrintStream out) -> 改变流向 ->让输出语句从控制台输出转移到指定文件中
properties结合IO流
1
2
3
4
5
6
7
8
9
10
11
12
概述: Properties extends Hashtable
特点:
a.无序,无索引
b.key唯一,value可重复
c.线程安全
d.key和value默认类型都是String

特有方法:
setProperty(String key,String value) 存键值对
getProperty(String key) -> 根据key获取value
stringPropertyNames()-> 获取所有的key存放到set集合中
load(InputStream in) -> 将流中的数据加载到Properties集合中
网络编程
正则表达式
新特性
反射
注解