java语言学习(8)

Java复习与泛型、线程知识学习

复习

强制类型转换

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]]

注:

  • 任意线程都可以开一个线程
  • 在控制台中输入JConsole 可以观察线程的存活情况
  • 调用start 才实现真正的多线程
  • start 调用 start0
  • start0() 是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虚拟机底层调用 start0
  • run 调用线程对象 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]]

释放锁

  • 当前线程的同步方法,同步代码块执行结束
  • 当前线程在同步代码块,同步方法中遇到break,return
  • 当前线程在同步代码块,同步代码块中出现了未处理的Error 或 Exception,导致异常结束
  • 当前线程在同步代码块,同步方法中执行了线程对象的 wait()方法,当前线程暂停,并释放锁

在这里插入图片描述

  • 输入流
    • inputStream
      • FileInputStream
      • BufferedInputStream
      • ObjectInputStream
    • Reader
      • FileReader
      • BufferedReader
      • ObjectReader
  • 输出流
    • OutputStream
      • FileOutputStream
      • BufferedOutputStream
      • ObjectOutputStream
    • Writer
      • FileWriter
      • BufferedWriter
      • ObjectWriter
  • Properities类

输入流 —> 数据进入java程序(内存)
输出流 —> 数据存储到文件(磁盘)

创建文件

  • new File(String pathname)
  • new File(File parent,String child)
  • new File(String parent,String chile)

读取文件

  • getName
  • getAbsolutePath
  • getParent
  • length
  • exists
  • isFile
  • isDirectory

目录的创建

  • mkdir()
  • `mkdirs() --> 创建多级目录
  • delete()

流的分类

  1. 按操作数单位不同分为:字节流(8bit)二进制文件,字符流(按字符)文本文件
  2. 按数据流的流向不同分为:输入流,输出流
  3. 按流的角色不同分为:节点流,处理流/包装流
  4. 这些都是抽象类,不能直接实例化
抽象基类字节流字符流
输入流InputStreamReader
输出流OutputStreamWriter

字节流

  • 字节输入流的常用的子类
    • 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();  
    }  
}

字符流

  • FileReader
    • new FileReader(File/String)
    • read() 每次读取单个字符,返回该字符,如果到末尾就返回 -1
    • read(char[]) 批量读取多个字符到数组,返回读取到的字符数,如果到末尾返回 -1
    • new String(char[])
    • new String(char[],off,len)
  • FileWriter
    • new 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"));

注:写入与这个类似

Properties类

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值