我的天啊一天又要過去了,沒事的還有時間!!!
不要焦慮不要焦慮,事實證明只要我認真地投入進去一切都還是來得及的,代碼多實操多復盤,別嘰嘰喳喳胡思亂想多多思考,有迷茫前害怕后的功夫已經可以學很多東西了,不許胡思亂想了快點學,,,對,加油,相信自己哦!!
---------------------------------------------------------------------------------------------------------------------------------
這是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
?類中的一個實例方法,其作用是返回當前線程對象的優先級。線程的優先級是一個介于?1
(Thread.MIN_PRIORITY
)到?10
(Thread.MAX_PRIORITY
)之間的整數,默認優先級為?5
(Thread.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;
?這種做法利用了多態性,提升了代碼的可擴展性和簡潔性。