当前位置: 首页 > news >正文

java复习 05

我的天啊一天又要过去了,没事的还有时间!!!

不要焦虑不要焦虑,事实证明只要我认真地投入进去一切都还是来得及的,代码多实操多复盘,别叽叽喳喳胡思乱想多多思考,有迷茫前害怕后的功夫已经可以学很多东西了,不许胡思乱想了快点学,,,对,加油,相信自己哦!!

---------------------------------------------------------------------------------------------------------------------------------

这是day2 写的,是的一般两天合起来更一次,一路生花~~~~❀~!!~!~!~!~!~!

加油加油加油!我的天啊期末考试慌死我了不会挂科的不会挂的不会的,,,吓鼠我了。。

pta还剩两道题目,记得看课了再做,做的太多了,今天要消化不良了。。。。。

1 设置和获取线程名称(小结)


Thread 类中设置和获取线程名称的方法

  • void setName (String name):将此线程的名称更改为等于参数 name
  • String getName ():返回此线程的名称
  • 通过构造方法也可以设置线程名称

如何获取 main () 方法所在的线程名称?

  • public static Thread currentThread ():返回对当前正在执行的线程对象的引用

2 线程调度

线程有两种调度模型~~~

  • 分时调度模型:所有线程轮流使用 CPU 的使用权,平均分配每个线程占用 CPU 的时间片
  • 抢占式调度模型:优先让优先级高的线程使用 CPU,如果线程的优先级相同,那么会随机选择一个,优先级高的线程获取的 CPU 时间片相对多一些

Java 使用的是抢占式调度模型

假如计算机只有一个 CPU,那么 CPU 在某一个时刻只能执行一条指令,线程只有得到 CPU 时间片,也就是使用权,才可以执行指令。所以说多线程程序的执行是有随机性,因为谁抢到 CPU 的使用权是不一定的!!

Thread 类中设置和获取线程优先级的方法

  • public final int getPriority ():返回此线程的优先级
  • public final void setPriority (int newPriority):更改此线程的优先级

public final int getPriority()

调用这个方法时,会返回当前线程对象的优先级。

返回值是一个 int 类型,在 Java 里,线程优先级的取值范围通常是 1(最低优先级 )到 10(最高优先级 ),默认值是5,(不过不同的 JVM 实现可能在具体映射到底层系统优先级时有差异,但应用层代码遵循这个取值逻辑即可 。

通过获取优先级,我们可以在程序中判断线程当前的 “重要程度” 设定,用于一些调试、日志记录或者逻辑判断场景,比如打印线程优先级信息,辅助排查多线程执行顺序相关问题 。

public final void setPriority(int newPriority)

该方法用于更改当前线程的优先级~~~~

传入的参数 newPriority 需是在合法取值范围(1 - 10 )内的 int 值。

需要注意的是,设置优先级只是给线程调度一个 “提示”!!!!!,并非设置后高优先级线程就一定会立即执行、低优先级线程就完全无法执行,它受抢占式调度整体机制以及系统环境等影响,但合理设置优先级,能在多线程协作执行中,让关键任务线程更大概率获得 CPU 资源,提升程序整体的执行效率和业务逻辑的合理性,比如在处理紧急任务的线程上设置较高优先级,让其尽快得到执行 。

 getPriority() :

是 Thread 类中的一个实例方法,其作用是返回当前线程对象的优先级。线程的优先级是一个介于 1Thread.MIN_PRIORITY)到 10Thread.MAX_PRIORITY)之间的整数,默认优先级为 5Thread.NORM_PRIORITY)。

package PTA_training.Thread_training;public class MyThreadDemo {public static void main(String[] args) {MyThread m1 = new MyThread("啊");MyThread m2 = new MyThread("ABC");// 设置 m1 的优先级为 10m1.setPriority(10);// 设置 m2 的优先级为 1m2.setPriority(1);// 启动线程m1.start();m2.start();}
}
package PTA_training.Thread_training;public class MyThread extends Thread {public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println(getName() + ":" + i);}}
}

3 线程控制

方法名说明
static void sleep(long millis)使当前正在执行的线程停留(暂停执行)指定的毫秒数
void join()等待这个线程死亡
void setDaemon(boolean on)将此线程标记为守护线程,当运行的线程都是守护线程时,Java 虚拟机将退出

4 消耗换行符的重要性

是的!在 Java 中使用 Scanner 时,输入流的换行符处理是非常容易出错的细节。以下是关于这个问题的深度解析和避坑指南,帮你彻底理解原理并避免类似问题:

一、为什么会出现换行符残留?

1. Scanner 的输入方法特性
  • nextInt()/nextDouble() 等方法
    只会读取有效数据部分(如数字),不会消耗数据后的换行符(\n,导致换行符残留在输入流中。
  • nextLine() 方法
    会读取一行完整的输入,包括换行符(但会自动去除换行符)。如果输入流中残留换行符,nextLine() 会直接读取空字符串。
2. 具体场景示例
  • 错误代码

    java

    int n = scanner.nextInt(); // 输入:3(回车)
    String line = scanner.nextLine(); // 此时 line 是空字符串!
    
     
    • 输入 3 后按下回车,nextInt() 读取 3,但残留 \n 在输入流中。
    • nextLine() 会直接读取这个残留的 \n(视为空行),导致 line 为空。
  • 正确做法
    在 nextInt() 后手动消耗换行符:

    java

    int n = scanner.nextInt(); 
    scanner.nextLine(); // 主动读取并丢弃残留的 \n
    String line = scanner.nextLine(); // 此时正常读取下一行输入
    

二、常见输入组合的坑与解决方案

1. 场景 1:数字 + 字符串(行输入)
  • 需求:先输入整数 n,再输入 n 行字符串(如姓名和年龄)。
  • 错误代码

    java

    int n = scanner.nextInt(); // 输入:3(回车)
    for (int i = 0; i < n; i++) {String line = scanner.nextLine(); // 第一次循环读取空字符串!// 导致 line.split(" ") 长度不足,引发 ArrayIndexOutOfBoundsException
    }
    
  • 解决方案
    在 nextInt() 后添加 scanner.nextLine() 消耗换行符:

    java

    int n = scanner.nextInt(); 
    scanner.nextLine(); // 关键!消耗残留的 \n
    for (int i = 0; i < n; i++) {String line = scanner.nextLine(); // 正常读取每一行String[] parts = line.split(" ");// ... 处理逻辑
    }
    
2. 场景 2:混合使用 next() 和 nextLine()
  • 需求:先输入单词(如姓名),再输入整行文本。
  • 错误代码

    java

    String name = scanner.next(); // 输入:lily(回车)
    String desc = scanner.nextLine(); // 直接读取空字符串!
    
  • 原因
    next() 读取到 lily 后,残留的 \n 被 nextLine() 视为空行。
  • 解决方案
    同样在 next() 后添加 scanner.nextLine() 消耗换行符(如果后续需要 nextLine()):

    java

    String name = scanner.next(); 
    scanner.nextLine(); // 消耗残留的 \n
    String desc = scanner.nextLine(); // 正常读取整行
    

三、终极避坑指南

1. 基本原则
  • 如果先调用了 nextInt()/next() 等非行读取方法,后续需要调用 nextLine() 时,必须手动消耗残留的换行符
  • **********
  • 养成习惯:在 nextInt()/next() 后,立即添加 scanner.nextLine() 来 “清理” 输入流。
2. 统一使用 nextLine() 处理输入
  • 对于数字输入,先读取整行字符串,再转为数字:

    java

    String nStr = scanner.nextLine(); // 读取整行(含回车)
    int n = Integer.parseInt(nStr); // 转为整数
    

    这样可以避免 nextInt() 遗留换行符的问题。
3. 调试技巧
  • 在怀疑输入流有残留时,添加 System.out.println("DEBUG: " + scanner.hasNextLine()); 查看是否有未读取的行。
  • 使用 scanner.hasNext() 或 scanner.hasNextInt() 预判输入类型,确保逻辑正确。

四、总结:为什么这个坑容易被忽略?

  • 换行符不可见:残留的 \n 不会在控制台显示,但会直接影响后续输入方法的行为。
  • 惯性思维:以为输入方法会自动处理所有字符,但实际上 Scanner 的不同方法对换行符的处理策略不同。

记住这个口诀:非行读取后,必消换行符

下次遇到类似问题时,先检查是否在 nextInt()/next() 后遗漏了 nextLine() 的调用~

 5 Express express;这是什么做法?划重点!

/*
7-5 快递计价器-2现需要编写一个简易快递计价程序。具体来说:1、抽象快递类Express,
其包含一个属性int weight表示快递重量(单位为kg),
一个方法getWeight()用于返回快递重量和一个抽象方法getTotal()用于计算快递运费。2、两个类继承Express,分别是:
(a)顺路快递SLExpress:计价规则为首重(1kg)12元,每增加1kg费用加2元。
(b)地地快递DDExpress:计价规则为首重(1kg)5元,每增加1kg费用加1元。3、Main:
接收用户通过控制台输入的N行信息,
自动计算每件快递的运费。输入样例:
6
SL 2
DD 2
SL 1
SL 1
SL 1
DD 3输入解释:
第1行n表示需要计算的快递件数
第2至n+1表示每个快递信息,
即选哪家快递公司 以及快递的重量(单位kg),
物品重量都是整数。输出样例:
SLExpress:14
DDExpress:6
SLExpress:12
SLExpress:12
SLExpress:12
DDExpress:7*/
import java.util.Scanner;
public class Main {public static void main(String[] args) {Scanner scanner = new Scanner(System.in);int n = scanner.nextInt();scanner.nextLine();for (int i = 0; i < n; i++) {String line = scanner.nextLine();String [] parts = line.split(" ");String name = parts[0];int weight = Integer.parseInt(parts[1]);Express express;//划重点,我卡住的地方if (name.equals("SL")){express = new SLExpress();express.weight = weight;System.out.println("SLExpress:"+ express.getTotal());} else if (name.equals("DD")) {express = new DDExpress();express.weight = weight;System.out.println("DDExpress:"+ express.getTotal());}else{continue;}}scanner.close();}
}
class SLExpress extends Express{@Overrideint getTotal(){if (weight > 1){return 12 + (weight - 1) * 2;}else {return 12;}}
}
class DDExpress extends Express{@Overrideint getTotal(){if (weight > 1){return 5 + (weight - 1 );}else {return 5;}}
}
abstract class Express {int weight;int getWeight(){return weight;}abstract int getTotal();
}

在你之前代码里出现的 Express express; 是一个变量声明语句,这是面向对象编程里多态性的一种应用,下面为你详细解释:

1. 变量声明

Express express; 声明了一个名为 express 的变量,该变量的类型为 Express。这里的 Express 是一个抽象类,此抽象类定义了快递的通用属性与方法,像 weight 属性、getWeight() 方法以及抽象方法 getTotal()

2. 多态性的体现

多态性是面向对象编程的重要特性之一,它允许我们使用父类类型的引用去引用子类的对象。在这个场景中,Express 是父类(抽象类),SLExpress 和 DDExpress 是它的子类。

在代码里,我们依据用户输入的快递公司名称(SL 或者 DD)来创建对应的子类对象,不过把这些子类对象赋值给父类类型的引用 express,具体代码如下:

java

if (name.equals("SL")) {express = new SLExpress();
} else if (name.equals("DD")) {express = new DDExpress();
}
  • 当 name 为 "SL" 时,创建一个 SLExpress 对象,并且把这个对象赋值给 express
  • 当 name 为 "DD" 时,创建一个 DDExpress 对象,并且把这个对象赋值给 express

3. 好处

采用这种做法有以下好处:

  • 代码的可扩展性:要是后续需要添加新的快递类型(例如新的子类),仅需创建新的子类并继承 Express 类,重写 getTotal() 方法,而不用修改 Main 类里大部分的代码逻辑。
  • 代码的简洁性:能够使用统一的父类引用 express 来调用 getTotal() 方法,不用为每个子类单独编写调用逻辑。例如:

java

express.weight = weight; // 设置快递重量
int total = express.getTotal(); // 计算运费

4. 动态绑定

在运行时,Java 会依据 express 实际引用的对象类型(SLExpress 或者 DDExpress)来调用对应的 getTotal() 方法,这就是动态绑定。所以,尽管 express 是 Express 类型的引用,但调用 getTotal() 方法时会执行子类重写后的具体实现。

综上所述,Express express; 这种做法利用了多态性,提升了代码的可扩展性和简洁性。

相关文章:

  • wpf在image控件上快速显示内存图像
  • 手动给中文分词和 直接用神经网络RNN做有什么区别
  • 如何利用 OpenCV 进行实时图像处理与对象检测
  • Python实例题:Python计算概率论
  • python打卡day48@浙大疏锦行
  • MCP(Model Context Protocol)模型上下文协议 番外篇 2025-03-26 更新
  • 鸿蒙学习笔记01
  • 第三章支线三 ·异步幻境 · 时间之缝的挑战
  • Redis 知识点一
  • 进程优先级
  • Spring注解开发
  • 原型对象(Prototype)详解
  • 二叉树-226.翻转链表-力扣(LeetCode)
  • Argo CD 入门 - 安装与第一个应用的声明式同步
  • OC—UI学习-2
  • 全志v853跑通rtsp sample
  • 阿里云Alibaba Cloud安装Docker与Docker compose【图文教程】
  • 创新滑模观测器设计:改进趋近律与切换函数的永磁同步电机无传感器控制
  • 65、.NET 中DllImport的用途
  • React、Git、计网、发展趋势等内容——前端面试宝典(字节、小红书和美团)
  • 广州个人做网站/线上商城推广软文
  • 公司做网站推广需要多少钱/企业宣传文案
  • wordpress 菜单跳转/1688关键词怎么优化
  • 寿光专业做网站的公司/西安优化排名推广
  • 大型网站建设的难点是什么/深圳百度关键词
  • 做app的网站有哪些功能/中层管理者培训课程有哪些