复习
强制类型转换
float d1 = 10 + 4.3;
// 4.3 会使得右边运算时会提升到double
//这样写是错的
//改写的两种方法
float d1 =10 + 4.3f;
double d1 = 10 + 4.3;
注: Java运算的时候,整数会默认变成int ,浮点数会默认变成 double
可变参数
class Dog(){
public int sum(int... nums){
//int... 表示接受的是可变参数,类型是int,即可以接收多个int(0——多)
//使用可变参数时,可以当作数组来使用,即nums 可以当作数组
//遍历nums求和即可
int res = 0;
for(int i = 0;i<nums.length;i++){
res += nums[i];
}
}
return res;
}
作用域
class dog{
// 公共的参数,都可以访问到
// 私有的,只有类的内部可以访问到
public String hobby1 = "踢足球";
private String hobby2 = "打篮球";
}
修饰符
- public : 对外公开
- protected :对子类和同一个包中的类公开
- 没有修饰 :向同一个包的类公开
- private : 只有类本身可以访问,不对外公开
继承
-
super 和 this 只能在构造器的第一行
- super ,调用父级构造器
- this ,调用自己的其他构造器
-
当常见子类对象时,不管使用子类的哪个构造器,默认情况下总会去调用父类的无参构造器,如果父类没有提供无参构造器,则必须在子类的构造器中使用super去指定使用父类的哪个构造器完成对父类的初始化工作,否则编译器会报错
多态
Animal animal = new Dog()- 编译类型是
Animal, 运行类型是Dog - instance
- 用于判断对象的类型是否为xx类型或者xx的子类型
== 与 equsls
- == 在判断引用类型的时候,判断的是地址是否相等
- equals 在自己写的类中如果有需求,需要重写
类变量和静态变量
public static int a = 5
final修饰
- 当一些东西不希望被改变的时候,使用
抽象类
- 不能被实例化
- 抽象类的子类必须实现它的抽象方法
枚举
enum Day {
MONDAY("星期一", 1),
TUESDAY("星期二", 2),
WEDNESDAY("星期三", 3),
THURSDAY("星期四", 4),
FRIDAY("星期五", 5),
SATURDAY("星期六", 6),
SUNDAY("星期日", 7);
private final String chineseName;
private final int index;
// 私有构造函数
Day(String chineseName, int index) {
this.chineseName = chineseName;
this.index = index;
}
// Getter方法
public String getChineseName() {
return chineseName;
}
public int getIndex() {
return index;
}
}
新知识
泛型
取出和放入都是泛型中的类型,不需要类型转换,效率高。
如果在泛型中添加了不符合的类型,就会报错,帮助代码的编写
泛型的作用
- 可以在类声明时通过一个标识标识某属性的类型
- 该标识可以时某个方法的返回值类型,或者是参数类型
class Dao<E>{
E e;
public void set(E e){
this.e = e;
}
public E get(){
return e;
}
}
Cat<String> a = new Cat<String>("123");
a.set("456");
System.out.println(a.get());
泛型的语法
interface 接口<T>{}class 类<K,V>{}- 泛型指定具体类型后,可以传入该类型或者其子类型
- 没有指定泛型时,默认为Object
- 静态方法中不能使用类的泛型
泛型的实例化
List<String> tem = new ArrayList<String>();
通配符
<?>支持任意泛型<? extends A>支持A类以及A的子类(规定了泛型的上限)<? super A>支持A以及A的父类(规定了泛型的下限)
测试
@Test- 然后
alt + ctrl
线程
概念
- 进程
- 指的是运行中的程序,操作系统会为其分配内存空间
- 线程
- 线程有进程创建,是进程的一个实体
- 一个进行可以拥有多个线程
- 单线程
- 在一个时刻,只允许执行一个线程
- 多线程
- 同一个时刻,可以执行多个线程
- 并发
- 在同一个时刻,多个任务交替执行(照成同时运行的错觉)
- 并行
- 一个时刻,多个任务同时执行
- 多核cpu可以实现并行
线程的基本使用
- 创建线程的两种方式
- 继承
Thread 类,重写run方法 - 实现
Runnable 接口,重写run方法
- 继承
基本使用
// 第一种继承 Thread 来实现多线程
class A extends Thread{
@Override
public void run() {
int i = 0;
while(true){
System.out.println("A");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
i++;
if(i == 10){
break;
}
}
}
}
// 调用写法
A a1 = new A();
a1.start();
// 第二种通过 Runnable 接口来实现多线程
class B implements Runnable{
@Override
public void run() {
int i = 0;
while(true){
System.out.println("B");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
i++;
if(i == 30){
break;
}
}
}
}
// 在主方法中调用
B b = new B();
Thread t1 = new Thread(b);
t1.start();
![![[Pasted image 20250719161929.png]]](https://i-blog.csdnimg.cn/direct/3a80d125bf12442292569d5fd69d8103.png)
注:
- 任意线程都可以开一个线程
- 在控制台中输入
JConsole可以观察线程的存活情况 调用start才实现真正的多线程start调用start0start0()是JVM调用, 由 c / c++ 实现
线程终止
// 通过外界更改loop ,来控制线程终止
class B implements Runnable{
private boolean loop = true;
@Override
public void run() {
int i = 0;
while(loop){
System.out.println("B");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
i++;
if(i == 30){
break;
}
}
}
public void setloop(boolean loop){
this.loop = loop;
}
}
线程常用方法
setName设置线程名称getName返回线程的名称start使线程开始执行,Java虚拟机底层调用start0run调用线程对象 run 方法setPriority更改线程的优先级getPriority获取线程的优先级sleep让当前的线程休眠interrupt中断线程,一般用于中断正在休眠线程
线程插队
yield,让出cpu, 让其他线程执行,但不一定成功join, 线程插队,插进去后,就一定会先执行插成功的
class Speak implements Runnable{
@Override
public void run() {
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("我是子线程");
}
}
}
public class ReData03_02 {
public static void main(String[] args) throws InterruptedException {
Thread thread = new Thread(new Speak());
for (int i = 0; i < 10; i++) {
System.out.println("我是主线程" + i);
if (i == 4){
thread.start();
thread.join();
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
用户线程和守护线程
- 用户线程:也叫工作线程,当线程的仍无执行完或通知方式结束
- 守护线程:一般是为工作线程服务的,当所有的用户线程结束,守护线程自动结束
常见额守护线程:垃圾回收机制
//在用户线程里
Thread thread = new Thread(new Speak_t());
thread.setDaemon(true);
thread.start();
//当用户线程噶了,守护线程也就挂了
线程状态
- NEW 尚未启动的线程处于此状态
- RUNNABLE 在Java虚拟机中执行的线程处于此状态
- BLOCKED 呗阻塞等待监视器锁定的线程
- WATTING 正在等待另一个线程执行特定动作的线程处于此状态
- TIMED_WAITING 正在等待另一个线程执行特定动作达到指定时间的线程处于此状态
- TERMINATED 以退出的线程处于此状态
1.1 NEW(新建)
-
状态描述:线程对象已创建,但尚未调用
start()方法。 -
示例代码:
Thread t = new Thread(() -> System.out.println("Running")); // 此时t处于NEW状态
1.2 RUNNABLE(可运行)
-
状态描述:线程已启动(调用
start()),正在 JVM 中运行或等待 CPU 资源。- 就绪(Ready):线程在就绪队列中,等待 CPU 调度。
- 运行中(Running):线程正在执行。
-
示例代码:
t.start(); // 调用start()后,t进入RUNNABLE状态
1.3 BLOCKED(阻塞)
- 状态描述:线程等待获取监视器锁(如
synchronized块),暂时无法执行。 - 触发场景:
-
试图进入同步代码块,但锁被其他线程持有。
-
示例代码:
public static synchronized void lockedMethod() { // 锁被占用时,其他线程进入BLOCKED状态 }
-
1.4 WAITING(无限等待)
-
状态描述:线程等待其他线程显式唤醒,否则不会恢复执行。
-
触发方法:
Object.wait()Thread.join()LockSupport.park()
-
示例代码:
synchronized (obj) { obj.wait(); // 当前线程进入WAITING状态,直到其他线程调用obj.notify() }
1.5 TIMED_WAITING(限时等待)
-
状态描述:线程在指定时间内等待,超时后自动唤醒。
-
触发方法:
Thread.sleep(long millis)Object.wait(long timeout)Thread.join(long millis)LockSupport.parkNanos()/parkUntil()
-
示例代码:
Thread.sleep(1000); // 当前线程暂停1秒,进入TIMED_WAITING状态
1.6 TERMINATED(终止)
- 状态描述:线程执行完毕或因异常退出,生命周期结束。
- 触发场景:
- 线程的
run()方法正常返回。 - 线程抛出未捕获的异常。
- 线程的
2. 状态转换图
NEW → start() → RUNNABLE ↔ BLOCKED
↓ ↑
wait()/join() ↔ TIMED_WAITING
↓ ↑
TERMINATED
线程同步机制
- 在多线程编程,一些敏感数据不允许被多个线程同步访问,此时就使用同步访问技术,保证数据在任何同一时刻,最多有一个线程访问,保证数据的完整性
使用方法
public synchronized boolean sell(int ticket) {
if(this.ticket <= 0){
return false;
}
try {
Thread.sleep(50);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName() + "抢到了第" + this.ticket + "张票");
this.ticket -= 1;
return true;
}
在方法中添加 synchronized 关键字
互斥锁
- 目的:保证共享数据的操作的完整性
- 保证在任意时刻,只能由一个线程访问该对象
- 同步的局限性:导致程序的执行效率要降低
- 同步方法(非静态)的锁可以是this,也可以是其他对象(只要是同一个实例就行)
- 同步方法(静态)的锁为当前类本身
注意事项
- 同步方法没有使用static修饰,默认锁对象为this
- 如果方法使用static 修饰,默认锁对象:当前类.claa
- 实现的落地步骤
- 需要先分析上锁的代码
- 选择同步代码块或同步方法
- 要求多个线程的锁对象为同一个即可
死锁
![![[Pasted image 20250721143823.png]]](https://i-blog.csdnimg.cn/direct/43893135b4a449d6954a4db11b89c48d.png)
释放锁
- 当前线程的同步方法,同步代码块执行结束
- 当前线程在同步代码块,同步方法中遇到break,return
- 当前线程在同步代码块,同步代码块中出现了未处理的Error 或 Exception,导致异常结束
- 当前线程在同步代码块,同步方法中执行了线程对象的 wait()方法,当前线程暂停,并释放锁

- 输入流
- inputStream
- FileInputStream
- BufferedInputStream
- ObjectInputStream
- Reader
- FileReader
- BufferedReader
- ObjectReader
- inputStream
- 输出流
- OutputStream
- FileOutputStream
- BufferedOutputStream
- ObjectOutputStream
- Writer
- FileWriter
- BufferedWriter
- ObjectWriter
- OutputStream
- Properities类
输入流 —> 数据进入java程序(内存)
输出流 —> 数据存储到文件(磁盘)
创建文件
new File(String pathname)new File(File parent,String child)new File(String parent,String chile)
读取文件
getNamegetAbsolutePathgetParentlengthexistsisFileisDirectory
目录的创建
mkdir()- `mkdirs() --> 创建多级目录
delete()
流的分类
- 按操作数单位不同分为:字节流(8bit)二进制文件,字符流(按字符)文本文件
- 按数据流的流向不同分为:输入流,输出流
- 按流的角色不同分为:节点流,处理流/包装流
- 这些都是抽象类,不能直接实例化
| 抽象基类 | 字节流 | 字符流 |
|---|---|---|
| 输入流 | InputStream | Reader |
| 输出流 | OutputStream | Writer |
字节流
字节输入流的常用的子类FileInputStream文件输入流read()read(bey[])- 如果读取成功,就返回读取的字节数,如果读取失败就返回 -1
- close(),在所有结束后,记得关闭这个输入流
FileOutputStream文件输出流write(byte[] b)- 注:字符串可以用
getBytes()方法 - 注:
append参数为true时,是追加 write(byte[] b, int off, int len)write(int b)
BufferedInputStream缓冲字节输入流ObjectInputStream对象字节输入流
FileInputStream read()示例
public class ReData05_03{
public static void getData() throws FileNotFoundException {
FileInputStream fis = new FileInputStream("D:/temp.txt");
int temInt = 0;
try {
while(((temInt = fis.read()) != -1)){
System.out.print((char)temInt);
}
}catch (IOException e) {
throw new RuntimeException(e);
}finally{
try {
fis.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) throws FileNotFoundException {
ReData05_03.getData();
}
}
FileOutputStreamwrite() 文件写入
package practice.ReData;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class ReData05_03 {
static FileOutputStream fos;
static {
try {
fos = new FileOutputStream("D:/temp.txt");
} catch (FileNotFoundException e) {
throw new RuntimeException(e);
}
}
public static void write(){
try {
fos.write("hello world cx!!".getBytes());
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}finally{
try {
fos.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
public static void main(String[] args) {
ReData05_03.write();
}
}
字符流
FileReadernew FileReader(File/String)read()每次读取单个字符,返回该字符,如果到末尾就返回 -1read(char[])批量读取多个字符到数组,返回读取到的字符数,如果到末尾返回 -1new String(char[])new String(char[],off,len)
FileWriternew FileWriter(File/String)覆盖模式,相当于流的指针在首端new FileWriter(File/String,true)追加模式,相当于流的指针在尾端writer(int)写入单个字符writer(char[])writer(char[],off,len)writer(string)writer(string,off,len)- 注:FileWriter使用后,必须要关闭(close) 或(flush),否则写入不到指定的文件
注:案例参照上面的字节流,只需要改实例化的对象为字符流就可以了
结点流和处理流
- 基本介绍
- 节点流:可以从一个特定的数据源读写数据
FileReader,FileWriter - 处理流(包装流):连接已存在的流,为程序提供更为强大的读写功能
BufferedReader,BufferedWriter
- 节点流:可以从一个特定的数据源读写数据
- 区别和联系
- 结点流是底层流,直接与数据源相接
- 处理流(包装流),即可以消除不同节点流的实现差异,也可以提供更方便的方法来完成输入输出
- 处理流对节点流进行包装,使用了修饰器设计模式,不会直接与数据源相连
- 处理流的功能主要体现
- 性能的提高:组要以增加缓冲的方式来提高输入输出的效率
- 操作的边界:处理流可提供一系列边界的方法来一次输入输出大批量的数据,使用更加灵活方便
BufferedReader案例
个人感觉:BufferedReader实际上是完成一步包装,让使用者在使用的时候,更加的方便
public class ReData06_02 {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new FileReader("D:/ReData06_01.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("D:/ReData06_02.txt"));
String str = null;
while((str = br.readLine()) != null){
bw.write(str);
bw.newLine();
}
br.close();
bw.close();
}
}
对象流
- 序列化和反序列化
- 序列化就是在保存数据时,保存数据的值和数据类型
- 反序列化就是在恢复数据时,恢复数据的值和数据类型
- 需要让某个对象支持序列化机制,则必须让其类时可序列化的,为了让某个类是可序列化的,该类必须实现如下两个接口之一
Serializable,这是一个标记接口,没有方法Externalizable,该接口有方法需要实现,因此外面一般实现上面的
- 基本介绍
- 提供了对基本类型或对象类型的序列化和反序列化的方法
ObjectOutputStream提供序列化功能ObjectInputStream提供反序列化功能- 如果我们希望调用存的类中的方法,需要向下转型
- 反序列化的时候,要将读取的数据类型写入
- 注意事项和细节说明
- 读写顺序要一致
- 要求实现序列化或反序列化对象需要实现Serializable
- 序列化的类中建议添加SerialVersionUID为了提高版本的兼容性
- 序列化对象时,默认将里面所有属性都进行序列化,但除了static或 transient修饰的成员
- 序列化对象时,要求里面属性的类型也需要实现序列化接口
- 序列化具备可继承性,也就是入宫某类已经实现了序列化,则它的所有子列也已经默认实现了序列化
代码示例
import java.io.*;
class Dog implements Serializable {
String name;
int age;
public Dog(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class ReData06_02 {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectOutputStream oos = null;
oos = new ObjectOutputStream(new FileOutputStream("D:/ReData06_02.txt"));
oos.writeUTF("hello world");
oos.writeObject(new Dog("旺财", 10));
oos.close();
ObjectInputStream ois = null;
ois = new ObjectInputStream(new FileInputStream("D:/ReData06_02.txt"));
String str = ois.readUTF();
System.out.println(str);
Dog dog = (Dog) ois.readObject();
System.out.println(dog.name + " " + dog.age);
}
}
标准输入输出流
System.in- 编译类型
InputStream - 运行类型
BufferedInputStream
- 编译类型
System.out- 编译类型
PrintStream - 运行类型
PrintStream
- 编译类型
import java.util.Scanner;
public class ReData06_02 {
public static void main(String[] args) {
System.out.println("你好");
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
System.out.println(str);
}
}
转换流
- InputStreamReader
- OutputStreamReader
注:可以指定处理的编码
InputStreamReader:Reader的子类,可以将InputStream(字节流)转换成Reader(字符流)OutputStreamReader:Writer的子类,可以将OutputStream(字节流)转换成Writer(字符流)- 当处理纯文本数据时,如果使用字符流效率更高,并且可以有效解决中文问题,所以建议将字节流转换成字符流
- utf-8,gbk,gb2312
可以指定编码的写法
BufferedReader br = new BufferedReader(
new InputStreamReader(new FileInputStream("D:/ReData06_01.txt"),"gbk"));
注:写入与这个类似
Java复习与泛型、线程知识学习

被折叠的 条评论
为什么被折叠?



