19.01_異常(異常的概述和分類)
- A:異常的概述
- 異常就是Java程序在運行過程中出現(xiàn)的錯誤。
- B:異常的分類
- 通過API查看Throwable
- Error
- 服務器宕機,數(shù)據(jù)庫崩潰等岔绸,比較嚴重的藕漱,無法控制的。
- Exception
- 異常 只要是程序運行沒有得到正常的結果,都屬于異常。
- int a = 10; int b = sc.nextInt(); int c = a / b; syso(c);
- int[] array = new int[10000];//椛0空間內(nèi)存不夠40000字節(jié)
C:異常的繼承體系
- Throwable
- Error
- Exception
- RuntimeException
19.02_異常(JVM默認是如何處理異常的)
- A:JVM默認是如何處理異常的
- main函數(shù)收到這個問題時,有兩種處理方式:
- a:自己將該問題處理,然后繼續(xù)運行
- b:自己沒有針對的處理方式,只有交給調用main的jvm來處理
- jvm有一個默認的異常處理機制,就將該異常進行處理.
- 并將該異常的名稱,異常的信息.異常出現(xiàn)的位置打印在了控制臺上,同時將程序停止運行
- B:案例演示
- JVM默認如何處理異常
19.03_異常(try...catch的方式處理異常1)
- A:異常處理的兩種方式
- a:try…catch…finally
- try catch
- try catch finally
- try finally
- 基本格式: try{
可能出現(xiàn)問題的代碼段【throw語句】;
}catch(異常類型1 引用名){
問題的解決方案拆火;
}catch(異常類型n 引用名){
問題的解決方案胞皱;
}finally{
額外釋放資源;
}
- b:throws
- a:try…catch…finally
- B:try...catch處理異常的基本格式
- try…catch…finally
- C:案例演示
- try...catch的方式處理1個異常
19.04_異常(try...catch的方式處理異常2)
- A:案例演示
- try...catch的方式處理多個異常
- JDK7以后處理多個異常的方式及注意事項
19.05_異常(編譯期異常和運行期異常的區(qū)別)
- A:編譯期異常和運行期異常的區(qū)別
Java中的異常被分為兩大類:編譯時異常和運行時異常酒贬。
所有的RuntimeException類及其子類的實例被稱為運行時異常考蕾,其他的異常就是編譯時異常
-
編譯時異常
- Java程序必須顯示處理[try-catch,throws],否則程序就會發(fā)生錯誤牌里,無法通過編譯
- 流相關的異常炊邦,就屬于編譯時異常
-
運行時異常
- 無需顯示處理[try-catch,throws]限寞,也可以和編譯時異常一樣處理
- 程序員所犯的錯誤,需要回來修改代碼【越界、空指針】
- B:案例演示
- 編譯期異常和運行期異常的區(qū)別
19.06_異常(Throwable的幾個常見方法,了解)
- A:Throwable的幾個常見方法
- a:getMessage()
- 獲取異常信息轧膘,返回字符串。
- b:toString()
- 獲取異常類名和異常信息赛惩,返回字符串趁餐。
- c:printStackTrace()
- 獲取異常類名和異常信息喷兼,以及異常出現(xiàn)在程序中的位置伍掀。返回值void。
- JVM默認處理方式
- a:getMessage()
- B:案例演示
- Throwable的幾個常見方法的基本使用
19.07_異常(throws的方式處理異常)
- A:throws的方式處理異常
- 定義功能方法時偷崩,需要把出現(xiàn)的問題暴露出來讓調用者去處理子姜。
- 那么就通過throws在方法上標識丰榴。
- B:注意
- 運行時異常业簿,拋出后可以不顯式處理【不寫throws】
- 編譯時異常窖杀,拋出后必須顯式處理【必須要寫throws】
- C:案例演示
- 舉例分別演示編譯時異常和運行時異常的拋出
- setAge(-17)
19.08_異常(throw的概述以及和throws的區(qū)別)
- A:throw的概述
- 程序員主動拋出異常
- 在功能方法內(nèi)部出現(xiàn)某種情況,程序不能繼續(xù)運行,需要進行跳轉時,就用throw把異常對象拋出。
- B:案例演示
- 分別演示編譯時異常對象和運行時異常對象的拋出
- C:throws和throw的區(qū)別
- a:throws
- 用在方法聲明后面,跟的是異常類名
- 可以跟多個異常類名,用逗號隔開
- 表示拋出異常,由該方法的調用者來處理
- b:throw
- 用在方法體內(nèi)宗雇,跟的是異常對象名
- 只能拋出一個異常對象名
- 表示拋出異常昂芜,由方法體內(nèi)的語句處理
- a:throws
19.09_異常(finally關鍵字的特點及作用)
- A:finally的特點
- 被finally控制的語句體一定會執(zhí)行
- 唯一的特殊情況:在執(zhí)行到finally之前jvm退出了(比如System.exit(0))
- B:finally的作用
- 用于釋放資源,在IO流操作和數(shù)據(jù)庫操作中會見到
- C:案例演示
- finally關鍵字的特點及作用
19.10_異常(finally關鍵字的面試題)
- A:面試題1
- final,finally和finalize的區(qū)別
- final可以修飾類赔蒲、方法泌神、變量
- finally是try語句中的一個語句體,用來釋放資源舞虱,不能單獨使用
- finalize是Object中一個方法欢际,當垃圾回收器回收類對象資源時,對象的垃圾回收器調用該方法矾兜。
- B:面試題2
- 如果catch里面有return語句损趋,請問finally的代碼還會執(zhí)行嗎? 如果會,請問是在return前還是return后椅寺?
- return先執(zhí)行建立返回路徑浑槽,然后finally執(zhí)行,最后return完全返回返帕。
19.11_異常(自定義異常概述和基本使用)
- A:為什么需要自定義異常
- 讓用戶根據(jù)異常名稱快速定位異常
- 舉例:人的年齡
- B:自定義異常概述
- 繼承自Exception
- 繼承自RuntimeException
- C:案例演示
- 自定義異常的基本使用
19.12_異常(異常的注意事項及如何使用異常處理)
- A:異常注意事項
- a:子類【重寫】父類方法時桐玻,子類的方法必須拋出【相同的異常】或父類異常的【子類】溉旋。(父親壞了,兒子不能比父親更壞)
- b:如果父類拋出了多個異常,子類重寫父類時,只能拋出相同的異常或者是他的子集,子類不能拋出父類沒有的異常
- c:如果被重寫的方法沒有異常拋出,那么子類的方法絕對不可以拋出異常,如果子類方法內(nèi)有異常發(fā)生,那么子類只能try,不能throws
- B:如何使用異常處理
原則:如果該功能內(nèi)部可以將問題處理,用try,如果處理不了,交由調用者處理,這是用throws
-
區(qū)別:
- 后續(xù)程序需要繼續(xù)運行就try
- 后續(xù)程序不需要繼續(xù)運行就throws
如果JDK沒有提供對應的異常嫉髓,需要自定義異常观腊。
19.13_異常(練習)
-
鍵盤錄入一個int類型的整數(shù),對其求二進制表現(xiàn)形式
- 如果錄入的整數(shù)過大,給予提示,錄入的整數(shù)過大請重新錄入一個整數(shù)BigInteger
- 如果錄入的是小數(shù),給予提示,錄入的是小數(shù),請重新錄入一個整數(shù)
- 如果錄入的是其他字符,給予提示,錄入的是非法字符,請重新錄入一個整數(shù)
alt + shift + z try-catch快捷鍵
try-catch的嵌套使用
Scanner sc = new Scanner(System.in);
System.out.println("請輸入一個整數(shù): ");while(true) {
String line = sc.nextLine();
try {
int num = Integer.parseInt(line);
System.out.println(Integer.toBinaryString(num));
break;
}catch(Exception e) {
try {
new BigInteger(line);//11111122.33333
System.out.println(錄入有誤,您錄入的是一個過大的整數(shù)!);
}catch(Exception e2){
try{
new BigDecimal(line);//11a1222.333
System.out.println("錄入錯誤算行,您錄入的是一個小數(shù)梧油,請重新輸入一個整數(shù): ");
}catch (Exception e1) {
System.out.println("錄入錯誤,您錄入的是非法字符州邢,請重新輸入一個整數(shù): ");
}
}
}
}儡陨;
19.14_File類(File類的概述和構造方法)
- A:File類的概述
- File更應該叫做一個路徑
- 文件路徑或者文件夾路徑
- 路徑分為絕對路徑和相對路徑
- 絕對路徑是一個固定的路徑,從盤符開始
- 相對路徑相對于某個位置,在eclipse下是指當前項目下,在dos下
- 查看API指的是當前路徑
- 文件和目錄路徑名的抽象表示形式
- File更應該叫做一個路徑
- B:構造方法
- File(String pathname):根據(jù)一個路徑得到File對象,注意分隔符F:\java
- File(String parent, String child):根據(jù)一個目錄和一個子文件/目錄得到File對象
- File(File parent, String child):根據(jù)一個父File對象和一個子文件/目錄得到File對象
- C:案例演示
- File類的構造方法
19.15_File類(File類的創(chuàng)建功能)
- A:創(chuàng)建功能
- public boolean createNewFile():創(chuàng)建文件 如果存在這樣的文件褪子,就不創(chuàng)建了
- public boolean mkdir():創(chuàng)建文件夾 如果存在這樣的文件夾,就不創(chuàng)建了
- public boolean mkdirs():創(chuàng)建多級文件夾,如果父文件夾不存在骗村,會幫你創(chuàng)建出來
- B:案例演示
File類的創(chuàng)建功能
-
注意事項:
- 如果你創(chuàng)建文件或者文件夾忘了寫盤符路徑嫌褪,那么,默認在項目路徑下胚股。
- 創(chuàng)建文件時可以不指定后綴笼痛,創(chuàng)建文件夾可以指定后綴
19.16_File類(File類的重命名和刪除功能)
- A:重命名和刪除功能
- public boolean renameTo(File dest):把文件重命名為指定的文件路徑或剪切
- public boolean delete():刪除文件或者文件夾
- B:重命名注意事項
- 如果路徑名相同,就是改名琅拌。
- 如果路徑名不同缨伊,就是改名并剪切。
- C:刪除注意事項:
- Java中的刪除不走回收站进宝。
- 要刪除一個文件夾刻坊,請注意該文件夾內(nèi)不能包含文件或者文件夾
19.17_File類(File類的判斷功能)
- A:判斷功能
- public boolean isDirectory():判斷是否是目錄
- public boolean isFile():判斷是否是文件
- public boolean exists():判斷是否存在
- public boolean canRead():判斷是否可讀,默認都是可讀党晋,setReadable無效
- public boolean canWrite():判斷是否可寫谭胚,可以設置
- public boolean isHidden():判斷是否隱藏,windows中先設置隱藏
- B:案例演示
- File類的判斷功能
19.18_File類(File類的獲取功能)
- A:獲取功能
- public String getAbsolutePath():獲取絕對路徑
- public String getPath():獲取路徑隶校,構造方法中傳入的
- public String getName():獲取名稱
- public long length():獲取長度漏益。字節(jié)數(shù)
- public long lastModified():獲取最后一次的修改時間,毫秒值
- public String[] list():獲取指定目錄下的所有文件或者文件夾的名稱數(shù)組
- public File[] listFiles():獲取指定目錄下的所有文件或者文件夾的File數(shù)組
- B:案例演示
- File類的獲取功能
19.19_File類(輸出指定目錄下指定后綴的文件名)
- A:案例演示
- 需求:判斷 E 目錄下是否有后綴名為.txt的文件深胳,如果有绰疤,就輸出該文件名稱
19.20_File類(文件名稱過濾器的概述及使用)
-
A:文件名稱過濾器的概述
- public String[] list(FilenameFilter filter)
- public File[] listFiles(FileFilter filter)
-
B:文件名稱過濾器的使用
- 需求:判斷E盤目錄下是否有后綴名為.jpg的文件,如果有舞终,就輸出該文件名稱
-
C:源碼分析
- 帶文件名稱過濾器的list()方法的源碼
file.list(new FilenameFilter() {
@Override
public boolean accept(File dir,String name) {
File f = new File(dir,name);
return f.isFile() && f.getName().endsWith(".jpg");
}
});
19.22_day19總結
把今天的知識點總結一遍轻庆。
20.01_IO流(IO流概述及其分類)
- 1.概念
- IO流用來處理設備之間的數(shù)據(jù)傳輸
- Java對數(shù)據(jù)的操作是通過流的方式
- Java用于操作流的類都在IO包中
- 流按流向分為兩種:輸入流,輸出流敛劝。
- 流按操作類型【單位】分為兩種:
- 字節(jié)流 : 字節(jié)流可以操作任何數(shù)據(jù),因為在計算機中任何數(shù)據(jù)都是以字節(jié)的形式存儲的
- 字符流 : 字符流只能操作純字符數(shù)據(jù)余爆,比較方便。
- 2.IO流常用父類
- 字節(jié)流的抽象父類:
- InputStream
- OutputStream
- 字符流的抽象父類:
- Reader
- Writer
- 字節(jié)流的抽象父類:
- 3.IO程序書寫
- 使用前夸盟,導入IO包中的類
- 使用時蛾方,進行IO異常處理
- 使用后,釋放資源
20.02_IO流(FileInputStream)
- read()一次讀取一個字節(jié)
FileInputStream fis = new FileInputStream("aaa.txt"); //創(chuàng)建一個文件輸入流對象,并關聯(lián)aaa.txt int b; //定義變量,記錄每次讀到的字節(jié) while((b = fis.read()) != -1) { //將每次讀到的字節(jié)賦值給b并判斷是否是-1 System.out.println(b); //打印每一個字節(jié) } fis.close(); //關閉流釋放資源
20.03_IO流(read()方法返回值為什么是int)
- read()方法讀取的是一個字節(jié),為什么返回是int,而不是byte
因為字節(jié)輸入流可以操作任意類型的文件,比如圖片音頻等,這些文件底層都是以二進制形式的存儲的,如果每次讀取都返回byte,有可能在讀到中間的時候遇到11111111 那么這11111111是byte類型的-1,我們的程序是遇到-1就會停止不讀了,后面的數(shù)據(jù)就讀不到了,所以在讀取的時候用int類型接收,如果11111111會在其前面補上 24個0湊足4個字節(jié),那么byte類型的-1就變成int類型的255了這樣可以保證整個數(shù)據(jù)讀完,而結束標記的-1就是int類型
20.04_IO流(FileOutputStream)
- write()一次寫出一個字節(jié)
FileOutputStream fos = new FileOutputStream("bbb.txt"); //如果沒有bbb.txt,會創(chuàng)建出一個 //fos.write(97); //雖然寫出的是一個int數(shù),但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte fos.write(98); fos.write(99); fos.close();
20.05_IO流(FileOutputStream追加)
- A:案例演示
- FileOutputStream的構造方法寫出數(shù)據(jù)如何實現(xiàn)數(shù)據(jù)的追加寫入
FileOutputStream fos = new FileOutputStream("bbb.txt",true); //如果沒有bbb.txt,會創(chuàng)建出一個 //fos.write(97); //雖然寫出的是一個int數(shù),但是在寫出的時候會將前面的24個0去掉,所以寫出的一個byte fos.write(98); fos.write(99); fos.close();
20.06_IO流(拷貝圖片)
- FileInputStream讀取
- FileOutputStream寫出
20.07_IO流(拷貝音頻文件畫原理圖)
-
A:案例演示
- 字節(jié)流一次讀寫一個字節(jié)復制音頻mp3文件
-
弊端:效率太低
FileInputStream fis = new FileInputStream("致青春.mp3"); //創(chuàng)建輸入流對象,關聯(lián)致青春.mp3 FileOutputStream fos = new FileOutputStream("copy.mp3");//創(chuàng)建輸出流對象,關聯(lián)copy.mp3 int b; while((b = fis.read()) != -1) { fos.write(b); } fos.close(); fis.close();
20.08_IO流(字節(jié)數(shù)組拷貝之a(chǎn)vailable()方法)
-
A:案例演示
- int read(byte[] b):一次讀取一個字節(jié)數(shù)組
- write(byte[] b):一次寫出一個字節(jié)數(shù)組
- available()獲取讀的文件所有的字節(jié)個數(shù)
-
弊端:有可能會內(nèi)存溢出
FileInputStream fis = new FileInputStream("致青春.mp3"); FileOutputStream fos = new FileOutputStream("copy.mp3"); byte[] arr = new byte[fis.available()]; //根據(jù)文件大小做一個字節(jié)數(shù)組 fis.read(arr); //將文件上的所有字節(jié)讀取到數(shù)組中 fos.write(arr); //將數(shù)組中的所有字節(jié)一次寫到了文件上 fis.close(); fos.close();
20.09_IO流(定義小數(shù)組)
- write(byte[] b)
- write(byte[] b, int off, int len)寫出有效的字節(jié)個數(shù)
20.10_IO流(定義小數(shù)組的標準格式)
- A:案例演示
-
字節(jié)流一次讀寫一個字節(jié)數(shù)組復制圖片和視頻
FileInputStream fis = new FileInputStream("致青春.mp3");
FileOutputStream fos = new FileOutputStream("copy.mp3");
int len;
byte[] arr = new byte[1024 * 8]; //自定義字節(jié)數(shù)組while((len = fis.read(arr)) != -1) {
//fos.write(arr);
fos.write(arr, 0, len); //寫出字節(jié)數(shù)組寫出有效個字節(jié)個數(shù)
}fis.close();
fos.close();
-
20.11_IO流(BufferedInputStream和BufferOutputStream拷貝)
-
A:緩沖思想
- 字節(jié)流一次讀寫一個數(shù)組的速度明顯比一次讀寫一個字節(jié)的速度快很多上陕,
- 這是加入了數(shù)組這樣的緩沖區(qū)效果桩砰,java本身在設計的時候,
- 也考慮到了這樣的設計思想(裝飾設計模式后面講解)释簿,所以提供了字節(jié)緩沖區(qū)流
-
B.BufferedInputStream
- BufferedInputStream內(nèi)置了一個緩沖區(qū)(數(shù)組)
- 從BufferedInputStream中讀取一個字節(jié)時
- BufferedInputStream會一次性從文件中讀取8192個, 存在緩沖區(qū)中, 返回給程序一個
- 程序再次讀取時, 就不用找文件了, 直接從緩沖區(qū)中獲取
- 直到緩沖區(qū)中所有的都被使用過, 才重新從文件中讀取8192個
-
C.BufferedOutputStream
- BufferedOutputStream也內(nèi)置了一個緩沖區(qū)(數(shù)組)
- 程序向流中寫出字節(jié)時, 不會直接寫到文件, 先寫到緩沖區(qū)中
- 直到緩沖區(qū)寫滿, BufferedOutputStream才會把緩沖區(qū)中的數(shù)據(jù)一次性寫到文件里
-
D.拷貝的代碼
FileInputStream fis = new FileInputStream("致青春.mp3"); //創(chuàng)建文件輸入流對象,關聯(lián)致青春.mp3 BufferedInputStream bis = new BufferedInputStream(fis); //創(chuàng)建緩沖區(qū)對fis裝飾 FileOutputStream fos = new FileOutputStream("copy.mp3"); //創(chuàng)建輸出流對象,關聯(lián)copy.mp3 BufferedOutputStr·eam bos = new BufferedOutputStream(fos); //創(chuàng)建緩沖區(qū)對fos裝飾 int b; while((b = bis.read()) != -1) { bos.write(b); } bis.close(); //只關裝飾后的對象即可 bos.close();
-
E.小數(shù)組的讀寫和帶Buffered的讀取哪個更快?
- 定義小數(shù)組如果是8192個字節(jié)大小和Buffered比較的話
- 定義小數(shù)組會略勝一籌,因為讀和寫操作的是同一個數(shù)組
- 而Buffered操作的是兩個數(shù)組
20.12_IO流(flush和close方法的區(qū)別)
- flush()方法
- 用來刷新緩沖區(qū)的,刷新后可以再次寫出
- close()方法
- 用來關閉流釋放資源的的,如果是帶緩沖區(qū)的流對象的close()方法,不但會關閉流,還會再關閉流之前刷新緩沖區(qū),關閉后不能再寫出
20.13_IO流(字節(jié)流讀寫中文)
- 字節(jié)流讀取中文的問題
- 字節(jié)流在讀中文的時候有可能會讀到半個中文,造成亂碼
- 字節(jié)流寫出中文的問題
- 字節(jié)流直接操作的字節(jié),所以寫出中文必須將字符串轉換成字節(jié)數(shù)組
- 寫出回車換行 write("\r\n".getBytes());
20.14_IO流(流的標準處理異常代碼1.6版本及其以前)
-
try finally嵌套
FileInputStream fis = null; FileOutputStream fos = null; try { fis = new FileInputStream("aaa.txt"); fos = new FileOutputStream("bbb.txt"); int b; while((b = fis.read()) != -1) { fos.write(b); } }catch (Exception e) { e.print...(); }finally { try { if(fis != null) fis.close(); }finally { if(fos != null) fos.close(); } }
20.15_IO流(流的標準處理異常代碼1.7版本)
-
try close 自動回收資源
try( FileInputStream fis = new FileInputStream("aaa.txt"); FileOutputStream fos = new FileOutputStream("bbb.txt"); //MyClose mc = new MyClose(); ){ int b; while((b = fis.read()) != -1) { fos.write(b); } }catch(Exception e) { ... }
-
原理
- 在try()中創(chuàng)建的流對象必須實現(xiàn)了AutoCloseable這個接口,如果實現(xiàn)了,在try后面的{}(讀寫代碼)執(zhí)行后就會自動調用,流對象的close方法將流關掉
20.16_IO流(圖片加密)
-
給圖片加密
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.jpg")); BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("b.jpg")); int b; while((b = bis.read()) != -1) { bos.write(b ^ 123); } bis.close(); bos.close();
20.17_IO流(拷貝文件) E://dir//a.txt
-
在控制臺錄入文件的路徑,將文件拷貝到當前項目下
Scanner sc = new Scanner(System.in); System.out.println("請輸入一個文件路徑"); String line = sc.nextLine(); //將鍵盤錄入的文件路徑存儲在line中 File file = new File(line); //封裝成File對象 FileInputStream fis = new FileInputStream(file); FileOutputStream fos = new FileOutputStream(file.getName()); int len; byte[] arr = new byte[8192]; //定義緩沖區(qū) while((len = fis.read(arr)) != -1) { fos.write(arr,0,len); } fis.close(); fos.close();
20.18_IO流(錄入數(shù)據(jù)拷貝到文件)
-
將鍵盤錄入的數(shù)據(jù)拷貝到當前項目下的text.txt文件中,鍵盤錄入數(shù)據(jù)當遇到quit時就退出
Scanner sc = new Scanner(System.in); FileOutputStream fos = new FileOutputStream("text.txt"); System.out.println("請輸入:"); while(true) { String line = sc.nextLine(); if("quit".equals(line)) break; fos.write(line.getBytes()); fos.write("\r\n".getBytes()); } fos.close();
21.01_IO流(字符流FileReader)
- 1.字符流是什么
- 字符流是可以直接讀寫字符的IO流
- 字符流讀取字符, 就要先讀取到字節(jié)數(shù)據(jù), 然后轉為字符. 如果要寫出字符, 需要把字符轉為字節(jié)再寫出.
- 只有純文本文件亚隅,我們才選擇 字符流進行操作啄育,提高我們效率旺聚,簡化操作
- 2.FileReader
- FileReader類的read()方法可以按照字符大小讀取
FileReader fr = new FileReader("aaa.txt"); //創(chuàng)建輸入流對象,關聯(lián)aaa.txt int ch; while((ch = fr.read()) != -1) { //將讀到的字符賦值給ch System.out.println((char)ch); //將讀到的字符強轉后打印 } fr.close(); //關流
21.02_IO流(字符流FileWriter)
FileWriter類的write()方法可以自動把字符轉為字節(jié)寫出
-
注意: Writer中自帶緩沖區(qū),注意刷新或關閉流。
FileWriter fw = new FileWriter("aaa.txt"); fw.write("aaa"); fw.close();
21.03_IO流(字符流的拷貝)
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("b.txt");
int ch;
while((ch = fr.read()) != -1) {
fw.write(ch);
}
fr.close();
fw.close();
21.04_IO流(什么情況下使用字符流)
- 字符流也可以拷貝文本文件, 但不推薦使用. 因為讀取時會把字節(jié)轉為字符, 寫出時還要把字符轉回字節(jié).
- 程序需要讀取一段文本, 或者需要寫出一段文本的時候可以使用字符流址貌。
- 讀取的時候是按照字符的大小讀取的,不會出現(xiàn)半個中文
- 寫出的時候可以直接將字符串寫出,不用轉換為字節(jié)數(shù)組
21.05_IO流(字符流是否可以拷貝非純文本的文件)
- 不可以拷貝非純文本的文件
- 因為在讀的時候會將字節(jié)轉換為字符,在轉換過程中,可能找不到對應的字符,就會用?代替,寫出的時候會將字符轉換成字節(jié)寫出去
- 如果是?,直接寫出,這樣寫出之后的文件就亂了,看不了了
21.06_IO流(自定義字符數(shù)組的拷貝)
FileReader fr = new FileReader("aaa.txt"); //創(chuàng)建字符輸入流,關聯(lián)aaa.txt FileWriter fw = new FileWriter("bbb.txt"); //創(chuàng)建字符輸出流,關聯(lián)bbb.txt int len; char[] arr = new char[1024*8]; //創(chuàng)建字符數(shù)組 while((len = fr.read(arr)) != -1) { //將數(shù)據(jù)讀到字符數(shù)組中 fw.write(arr, 0, len); //從字符數(shù)組將數(shù)據(jù)寫到文件上 } fr.close(); //關流釋放資源 fw.close();
21.07_IO流(帶緩沖的字符流)
- BufferedReader的read()方法讀取字符時會一次讀取若干字符到緩沖區(qū), 然后逐個返回給程序, 降低讀取文件的次數(shù), 提高效率
- BufferedWriter的write()方法寫出字符時會先寫到緩沖區(qū), 緩沖區(qū)寫滿時才會寫到文件, 降低寫文件的次數(shù), 提高效率
BufferedReader br = new BufferedReader(new FileReader("aaa.txt")); //創(chuàng)建字符輸入流對象,關聯(lián)aaa.txt BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt")); //創(chuàng)建字符輸出流對象,關聯(lián)bbb.txt int ch; while((ch = br.read()) != -1) { //read一次,會先將緩沖區(qū)讀滿,從緩沖去中一個一個的返給臨時變量ch bw.write(ch); //write一次,是將數(shù)據(jù)裝到字符數(shù)組,裝滿后再一起寫出去 } br.close(); //關流 bw.close();
21.08_IO流(readLine()和newLine()方法)
- BufferedReader的readLine()方法可以讀取一行字符(不包含換行符號)
- BufferedWriter的newLine()可以輸出一個跨平臺的換行符號"\r\n"
BufferedReader br = new BufferedReader(new FileReader("aaa.txt")); BufferedWriter bw = new BufferedWriter(new FileWriter("bbb.txt")); String line; while((line = br.readLine()) != null) { bw.write(line); //bw.write("\r\n"); //只支持windows系統(tǒng) bw.newLine(); //跨平臺的 } br.close(); bw.close();
21.09_IO流(將文本反轉)
- 將一個文本文檔上的文本反轉,第一行和倒數(shù)第一行交換,第二行和倒數(shù)第二行交換
21.10_IO流(LineNumberReader) 了解
- LineNumberReader是BufferedReader的子類, 具有相同的功能, 并且可以統(tǒng)計行號
- 調用getLineNumber()方法可以獲取當前行號
- 調用setLineNumber()方法可以設置當前行號
LineNumberReader lnr = new LineNumberReader(new FileReader("aaa.txt")); String line; lnr.setLineNumber(100); //設置行號 while((line = lnr.readLine()) != null) { System.out.println(lnr.getLineNumber() + ":" + line);//獲取行號 } lnr.close();
21.11_IO流(裝飾設計模式)
- 設計模式: 前人總結的乡摹,為了解決特定場景問題所提出的解決方案弱匪,常用的有23種畔裕,很巧妙,提高程序員工作效率【遇到類似問題隘擎,直接套用對應的設計模式即可】殴穴。
- 可以對類功能進行增強,同時保證低耦合
- IO流中類 就是裝飾模式的具體應用货葬。
//公共接口 interface Coder { public void code(); } //具體類 class Student implements Coder { @Override public void code() { System.out.println("javase"); System.out.println("javaweb"); } } //裝飾器類 class BriupStudent implements Coder { private Student s; //獲取到被包裝的類的引用 public BriupStudent(Student s) { //通過構造函數(shù)創(chuàng)建對象的時候,傳入被包裝的對象 this.s = s; } @Override public void code() { //對其原有功能進行升級 s.code(); System.out.println("唱歌"); System.out.println("跳舞"); System.out.println("做飯"); System.out.println("洗衣服"); } } //編碼: 開閉原則【對修改關閉采幌,對擴展開放】 main() { //Coder stu = new Student(); //stu.code(); Coder stu = new BriupStudent(new Student()); stu.code(); }
21.12_IO流(使用指定的碼表讀寫字符)
- FileReader是使用默認碼表讀取文件, 如果需要使用指定碼表讀取, 那么可以使用InputStreamReader(字節(jié)流,編碼表)
- FileWriter是使用默認碼表寫出文件, 如果需要使用指定碼表寫出, 那么可以使用OutputStreamWriter(字節(jié)流,編碼表)
BufferedReader br = //高效的用指定的編碼表讀 new BufferedReader(new InputStreamReader(new FileInputStream("UTF-8.txt"), "UTF-8")); BufferedWriter bw = //高效的用指定的編碼表寫 new BufferedWriter(new OutputStreamWriter(new FileOutputStream("GBK.txt"), "GBK")); int ch; while((ch = br.read()) != -1) { bw.write(ch); } br.close(); bw.close();
21.13_IO流(轉換流圖解)
- 畫圖分析轉換流
21.14_IO流(獲取文本上字符出現(xiàn)的次數(shù))
- 獲取一個文本上每個字符出現(xiàn)的次數(shù),將結果寫在times.txt上
- TreeMap 字符 次數(shù) Test7Count.java
- a: 10 緩沖流
- b: 13
- 中: 16
21.15_IO流(試用版軟件)
- 當我們下載一個試用版軟件,沒有購買正版的時候,每執(zhí)行一次就會提醒我們還有多少次使用機會用學過的IO流知識,模擬試用版軟件,試用10次機會,執(zhí)行一次就提示一次您還有幾次機會,如果次數(shù)到了提示請購買正版
- 配置信息 軟件安裝的時間 配置文件config.txt
- 一個月以內(nèi)可以正常使用,一個月以后就無法使用震桶,提示你購買正版.
21.16_File類(遞歸)
- 函數(shù)自己調用自己休傍,就是遞歸
- 注意: 書寫遞歸函數(shù),一定要設置結束條件蹲姐,不能讓程序一直遞歸下去磨取。
- 遞歸的好處,在特定場景中很容易幫助理解柴墩;弊端是效率低忙厌,還可能造成棧內(nèi)存溢出
- 5的階乘
- 波非那切數(shù) 1 1 2 3 5 8 13 21 34 55
- f(n){//5
- if(n == 1 || n == 2)
return 1;
- return f(n-1) + f(n-2);
- }
21.17_File類(練習)
- 需求:從鍵盤輸入接收一個文件夾路徑,打印出該文件夾下所有的.java文件名
21.18_File類遞歸練習(統(tǒng)計該文件夾大小)
- 需求:1,從鍵盤接收一個文件夾路徑,統(tǒng)計該文件夾大小
- 求一個目錄的長度: 求出來所有子文件 的長度和
- E:\a的大小: test.java + dir1大小 + dir2大小
- E:\a\test.java
- E:\a\dir1\a.txt
- E:\a\dir2\b.txt c.txt
21.19_IO流(總結)
- 1.會用BufferedReader讀取GBK碼表和UTF-8碼表的字符
- 2.會用BufferedWriter寫出字符到GBK碼表和UTF-8碼表的文件中
- 3.會使用BufferedReader從鍵盤讀取一行
22.01_IO流(序列流)(了解)
- 1.什么是序列流
- 序列流可以把多個字節(jié)輸入流整合成一個, 從序列流中讀取數(shù)據(jù)時, 將從被整合的第一個流開始讀, 讀完一個之后繼續(xù)讀第二個, 以此類推.
- 2.使用方式
- 整合兩個: SequenceInputStream(InputStream, InputStream)
FileInputStream fis1 = new FileInputStream("a.txt"); //創(chuàng)建輸入流對象,關聯(lián)a.txt FileInputStream fis2 = new FileInputStream("b.txt"); //創(chuàng)建輸入流對象,關聯(lián)b.txt SequenceInputStream sis = new SequenceInputStream(fis1, fis2); //將兩個流整合成一個流 FileOutputStream fos = new FileOutputStream("c.txt"); //創(chuàng)建輸出流對象,關聯(lián)c.txt int b; while((b = sis.read()) != -1) { //用整合后的讀 fos.write(b); //寫到指定文件上 } sis.close(); fos.close();
22.02_IO流(序列流整合多個)(了解)
- 整合多個: SequenceInputStream(Enumeration)
FileInputStream fis1 = new FileInputStream("a.txt"); //創(chuàng)建輸入流對象,關聯(lián)a.txt FileInputStream fis2 = new FileInputStream("b.txt"); //創(chuàng)建輸入流對象,關聯(lián)b.txt FileInputStream fis3 = new FileInputStream("c.txt"); //創(chuàng)建輸入流對象,關聯(lián)c.txt Vector<InputStream> v = new Vector<>(); //創(chuàng)建vector集合對象 v.add(fis1); //將流對象添加 v.add(fis2); v.add(fis3); Enumeration<InputStream> en = v.elements(); //獲取枚舉引用 SequenceInputStream sis = new SequenceInputStream(en); //傳遞給SequenceInputStream構造 FileOutputStream fos = new FileOutputStream("d.txt"); int b; while((b = sis.read()) != -1) { fos.write(b); } sis.close(); fos.close();
22.03_IO流(內(nèi)存輸出流*****)(掌握)
- 1.什么是內(nèi)存輸出流
- 該輸出流可以向內(nèi)存中寫數(shù)據(jù), 把內(nèi)存當作一個緩沖區(qū), 寫出之后可以一次性獲取出所有數(shù)據(jù)
- 2.使用方式
- 創(chuàng)建對象: new ByteArrayOutputStream()
- 寫出數(shù)據(jù): write(int), write(byte[])
- 獲取數(shù)據(jù): toByteArray() toString()
FileInputStream fis = new FileInputStream("a.txt"); ByteArrayOutputStream baos = new ByteArrayOutputStream(); int b; while((b = fis.read()) != -1) { baos.write(b); } //byte[] newArr = baos.toByteArray(); //將內(nèi)存緩沖區(qū)中所有的字節(jié)存儲在newArr中 //System.out.println(new String(newArr)); System.out.println(baos); fis.close();
22.04_IO流(內(nèi)存輸出流之面試題)(掌握)
- 定義一個文件輸入流,調用read(byte[] b)方法,將a.txt文件中的內(nèi)容打印出來(byte數(shù)組大小限制為5)
FileInputStream fis = new FileInputStream("a.txt"); //創(chuàng)建字節(jié)輸入流,關聯(lián)a.txt ByteArrayOutputStream baos = new ByteArrayOutputStream(); //創(chuàng)建內(nèi)存輸出流 byte[] arr = new byte[5]; //創(chuàng)建字節(jié)數(shù)組,大小為5 int len; while((len = fis.read(arr)) != -1) { //將文件上的數(shù)據(jù)讀到字節(jié)數(shù)組中 baos.write(arr, 0, len); //將字節(jié)數(shù)組的數(shù)據(jù)寫到內(nèi)存緩沖區(qū)中 } System.out.println(baos); //將內(nèi)存緩沖區(qū)的內(nèi)容轉換為字符串打印 fis.close();
22.05_IO流(對象操作流ObjectOutputStream)(重點掌握)
- 1.什么是對象操作流
- 該流可以將一個對象寫出, 或者讀取一個對象到程序中. 也就是執(zhí)行了序列化和反序列化的操作.
- 2.使用方式
-
寫出: new ObjectOutputStream(OutputStream), writeObject()
public class Demo3_ObjectOutputStream { /** * @param args * @throws IOException * 將對象寫出,序列化 */ public static void main(String[] args) throws IOException { Person p1 = new Person("張三", 23); Person p2 = new Person("李四", 24); // FileOutputStream fos = new FileOutputStream("e.txt"); // fos.write(p1); // FileWriter fw = new FileWriter("e.txt"); // fw.write(p1); //無論是字節(jié)輸出流,還是字符輸出流都不能直接寫出對象 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("e.txt"));//創(chuàng)建對象輸出流 oos.writeObject(p1); oos.writeObject(p2); oos.close(); } }
-
22.06_IO流(對象操作流ObjectInputStream)(了解)
- 讀取: new ObjectInputStream(InputStream), readObject()
public class Demo3_ObjectInputStream { /** * @param args * @throws IOException * @throws ClassNotFoundException * @throws FileNotFoundException * 讀取對象,反序列化 */ public static void main(String[] args) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("e.txt")); Person p1 = (Person) ois.readObject(); Person p2 = (Person) ois.readObject(); System.out.println(p1); System.out.println(p2); ois.close(); } }
22.07_IO流(對象操作流優(yōu)化)(了解)
* 將對象存儲在集合中寫出
Person p1 = new Person("張三", 23);
Person p2 = new Person("李四", 24);
Person p3 = new Person("馬哥", 18);
Person p4 = new Person("輝哥", 20);
ArrayList<Person> list = new ArrayList<>();
list.add(p1);
list.add(p2);
list.add(p3);
list.add(p4);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("f.txt"));
oos.writeObject(list); //寫出集合對象
oos.close();
-
讀取到的是一個集合對象
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("f.txt")); ArrayList<Person> list = (ArrayList<Person>)ois.readObject(); //泛型在運行期會被擦除,索引運行期相當于沒有泛型 //想去掉黃色可以加注解 @SuppressWarnings("unchecked") for (Person person : list) { System.out.println(person); } ois.close();
22.08_IO流(加上id號)(了解)
- 注意
- 要寫出的對象必須實現(xiàn)Serializable接口才能被序列化
- 不用必須加id號
22.09_IO流(打印流的概述和特點)(掌握)
- 1.什么是打印流
該流可以很方便的將對象的toString()結果輸出, 并且自動加上換行, 而且可以使用【自動刷出】的模式
-
System.out就是一個PrintStream, 其默認向控制臺輸出信息
PrintStream ps = System.out; ps.println(97); //其實底層用的是Integer.toString(x),將x轉換為數(shù)字字符串打印 ps.println("xxx"); ps.println(new Person("張三", 23)); Person p = null; ps.println(p); //如果是null,就返回null,如果不是null,就調用對象的toString()
- 2.使用方式
打印: print(), println()
自動刷出: PrintWriter(OutputStream out, boolean autoFlush, String encoding) 江咳,只針對println方法逢净,沒什么大用處。
-
打印流只操作【數(shù)據(jù)目的】
PrintWriter pw = new PrintWriter(new FileOutputStream("g.txt"), true); pw.write(97); pw.print("大家好"); pw.println("你好"); //自動刷出,只針對的是println方法 pw.close();
22.10_IO流(標準輸入輸出流概述和輸出語句)
- 1.什么是標準輸入輸出流(掌握)
- System.in是InputStream, 標準輸入流, 默認可以從鍵盤輸入讀取字節(jié)數(shù)據(jù)
- System.out是PrintStream, 標準輸出流, 默認可以向Console中輸出字符和字節(jié)數(shù)據(jù)
- 2.修改標準輸入輸出流(了解)
- 修改輸入流: System.setIn(InputStream)
- 修改輸出流: System.setOut(PrintStream)
System.setIn(new FileInputStream("a.txt")); //修改標準輸入流 System.setOut(new PrintStream("b.txt")); //修改標準輸出流 InputStream in = System.in; //獲取標準輸入流 PrintStream ps = System.out; //獲取標準輸出流 int b; while((b = in.read()) != -1) { //從a.txt上讀取數(shù)據(jù) ps.write(b); //將數(shù)據(jù)寫到b.txt上 } in.close(); ps.close();
22.11_IO流(修改標準輸入輸出流拷貝圖片)(了解)
System.setIn(new FileInputStream("IO圖片.png")); //改變標準輸入流
System.setOut(new PrintStream("copy.png")); //改變標準輸出流
InputStream is = System.in; //獲取標準輸入流
PrintStream ps = System.out; //獲取標準輸出流
int len;
byte[] arr = new byte[1024 * 8];
while((len = is.read(arr)) != -1) {
ps.write(arr, 0, len);
}
is.close();
ps.close();
22.11_IO流(兩種方式實現(xiàn)鍵盤錄入)(了解)
- A:BufferedReader的readLine方法
- BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
- B:Scanner方式
22.12_IO流(隨機訪問流概述和讀寫數(shù)據(jù))(了解)
-
A:隨機訪問流概述
- RandomAccessFile概述
- RandomAccessFile類不屬于流歼指,是Object類的子類爹土。但它融合了InputStream和OutputStream的功能。
- 支持對隨機訪問文件的讀取和寫入踩身。
-
B:read(),write(),seek()
- seek從0開始
22.13_IO流(數(shù)據(jù)輸入輸出流)(了解)
- 1.什么是數(shù)據(jù)輸入輸出流
- DataInputStream, DataOutputStream可以按照基本數(shù)據(jù)類型大小讀寫數(shù)據(jù)
- 例如按Long大小寫出一個數(shù)字, 寫出時該數(shù)據(jù)占8字節(jié). 讀取的時候也可以按照Long類型讀取, 一次讀取8個字節(jié).
- 2.使用方式
-
DataOutputStream(OutputStream), writeInt(), writeLong()
DataOutputStream dos = new DataOutputStream(new FileOutputStream("b.txt")); dos.writeInt(997); dos.writeInt(998); dos.writeInt(999); dos.close();
-
DataInputStream(InputStream), readInt(), readLong()
DataInputStream dis = new DataInputStream(new FileInputStream("b.txt")); int x = dis.readInt(); int y = dis.readInt(); int z = dis.readInt(); System.out.println(x); System.out.println(y); System.out.println(z); dis.close();
-
22.14_IO流(Properties的概述和作為Map集合的使用)(掌握)
- A:Properties的概述
- Properties 類表示了一個持久的屬性集胀茵。
- Properties 可保存在流中或從流中加載。
- 屬性列表中每個鍵及其對應值都是一個字符串挟阻。
- B:案例演示
- Properties作為Map集合的使用
22.15_IO流(Properties的特殊功能使用)(掌握)
- A:Properties的特殊功能
- public Object setProperty(String key,String value)
- public String getProperty(String key)
- public Set<String> stringPropertyNames()
- B:案例演示
- Properties的特殊功能
22.16_IO流(Properties的load()和store()功能)(了解)
- A:Properties的load()和store()功能
- B:案例演示
- Properties的load()和store(OutputStream out,String comments)功能琼娘;
- String comments是對列表參數(shù)的描述,null與非null值都可以附鸽。
24.01_多線程(多線程的引入)(了解)
- 1.什么是線程
- 線程是程序執(zhí)行的一條路徑, 一個進程中可以包含多條線程
- QQ聊天 進程 你在給同學發(fā)信息的同時脱拼,能否接收其他同學的消息?提高效率
- 進程拒炎,是一個應用程序的執(zhí)行流程挪拟,進程是資源分配的最小單位
- 多線程并發(fā)執(zhí)行可以提高程序的效率, 可以同時完成多項工作
- 2.多線程的應用場景
- 紅蜘蛛同時共享屏幕給多個電腦
- 迅雷開啟多條線程一起下載
- QQ同時和多個人一起視頻
- 服務器同時處理多個客戶端請求
24.02_多線程(多線程并行和并發(fā)的區(qū)別)(了解)
- 并行就是兩個任務同時運行挨务,就是甲任務進行的同時击你,乙任務也在進行玉组。(需要多核CPU)
- 并發(fā)是指兩個任務都請求運行,而處理器只能按受一個任務丁侄,就把這兩個任務安排輪流進行惯雳,由于時間間隔較短,使人感覺兩個任務都在運行鸿摇。
- 比如我跟兩個網(wǎng)友聊天石景,左手操作一個電腦跟甲聊,同時右手用另一臺電腦跟乙聊天拙吉,這就叫并行潮孽。
- 如果用一臺電腦我先給甲發(fā)個消息,然后立刻再給乙發(fā)消息筷黔,然后再跟甲聊往史,再跟乙聊。這就叫并發(fā)佛舱。
24.03_多線程(Java程序運行原理和JVM的啟動是多線程的嗎)(了解)
-
A:Java程序運行原理
- Java命令會啟動java虛擬機椎例,啟動JVM,等于啟動了一個應用程序请祖,也就是啟動了一個進程订歪。該進程會自動啟動一個 “主線程” ,然后主線程去調用某個類的 main 方法肆捕。
-
B:JVM的啟動是多線程的嗎
- JVM啟動至少啟動了垃圾回收線程和主線程刷晋,所以是多線程的。
24.04_多線程(多線程程序實現(xiàn)的方式1)(掌握)
- 1.繼承Thread
- 定義類繼承Thread
- 重寫run方法
- 把新線程要做的事寫在run方法中
- 創(chuàng)建線程對象
- 開啟新線程, 內(nèi)部會自動執(zhí)行run方法
public class Demo2_Thread { /** * @param args */ public static void main(String[] args) { MyThread mt = new MyThread(); //4,創(chuàng)建自定義類的對象 mt.start(); //5,開啟線程 for(int i = 0; i < 3000; i++) { System.out.println("bb"); } } } class MyThread extends Thread { //1,定義類繼承Thread public void run() { //2,重寫run方法 for(int i = 0; i < 3000; i++) { //3,將要執(zhí)行的代碼,寫在run方法中 System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } } }
24.05_多線程(多線程程序實現(xiàn)的方式2)(掌握)
- 2.實現(xiàn)Runnable
定義類實現(xiàn)Runnable接口
實現(xiàn)run方法
把新線程要做的事寫在run方法中
創(chuàng)建自定義的Runnable的子類對象
創(chuàng)建Thread對象, 傳入Runnable
-
調用start()開啟新線程, 內(nèi)部會自動調用Runnable的run()方法
public class Demo3_Runnable { /** * @param args */ public static void main(String[] args) { MyRunnable mr = new MyRunnable(); //4,創(chuàng)建自定義類對象 //Runnable target = new MyRunnable(); Thread t = new Thread(mr); //5,將其當作參數(shù)傳遞給Thread的構造函數(shù) t.start(); //6,開啟線程 for(int i = 0; i < 3000; i++) { System.out.println("bb"); } } } class MyRunnable implements Runnable { //1,自定義類實現(xiàn)Runnable接口 @Override public void run() { //2,重寫run方法 for(int i = 0; i < 3000; i++) { //3,將要執(zhí)行的代碼,寫在run方法中 System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } } }
24.06_多線程(實現(xiàn)Runnable的原理)(了解)
- 查看源碼
- 1,看Thread類的構造函數(shù),傳遞了Runnable接口的引用
- 2,通過init()方法找到傳遞的target給成員變量的target賦值
- 3,查看run方法,發(fā)現(xiàn)run方法中有判斷,如果target不為null就會調用Runnable接口子類對象的run方法
24.07_多線程(兩種方式的區(qū)別)(掌握)
-
查看源碼的區(qū)別:
- a.繼承Thread: 由于子類重寫了Thread類的run(), 當調用start()時, 直接找子類的run()方法
- b.實現(xiàn)Runnable: 構造函數(shù)中傳入了Runnable的引用, 成員變量記住了它, start()調用run()方法時內(nèi)部判斷成員變量Runnable的引用是否為空, 不為空編譯時看的是Runnable的run(),運行時執(zhí)行的是子類的run()方法
- 好處是:可以直接使用Thread類中的方法,代碼簡單繼承Thread
- 弊端是:如果已經(jīng)有了父類,就不能用這種方法
-
實現(xiàn)Runnable接口
- 好處是:即使自己定義的線程類有了父類也沒關系,因為有了父類也可以實現(xiàn)接口,而且接口是可以多實現(xiàn)的
- 弊端是:不能直接使用Thread中的方法需要先獲取到線程對象后,才能得到Thread的方法,代碼復雜
24.08_多線程(匿名內(nèi)部類實現(xiàn)線程的兩種方式)(掌握)
-
繼承Thread類
new Thread() { //1,new 類(){}繼承這個類 public void run() { //2,重寫run方法 for(int i = 0; i < 3000; i++) { //3,將要執(zhí)行的代碼,寫在run方法中 System.out.println("aaaaaaaaaaaaaaaaaaaaaaaaaaaa"); } } }.start();
-
實現(xiàn)Runnable接口
new Thread(new Runnable(){ //1,new 接口(){}實現(xiàn)這個接口 public void run() { //2,重寫run方法 for(int i = 0; i < 3000; i++) { //3,將要執(zhí)行的代碼,寫在run方法中 System.out.println("bb"); } } }).start();
24.09_多線程(獲取名字和設置名字)(掌握)
- 1.獲取名字
- 通過getName()方法獲取線程對象的名字
- 線程對象 有默認的名稱福压,命名方式: Thread-n 或 main
- 2.設置名字
- 通過構造函數(shù)可以傳入String類型的名字
new Thread("xxx") { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(this.getName() + "....aaaaaaaaaaaaaaaaaaaaaaa"); } } }.start(); new Thread("yyy") { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(this.getName() + "....bb"); } } }.start();
- 通過setName(String)方法可以設置線程對象的名字
Thread t1 = new Thread() { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(this.getName() + "....aaaaaaaaaaaaaaaaaaaaaaa"); } } }; Thread t2 = new Thread() { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(this.getName() + "....bb"); } } }; t1.setName("芙蓉姐姐"); t2.setName("鳳姐"); t1.start(); t2.start();
24.10_多線程(獲取當前線程的對象)(掌握)
- Thread.currentThread(), 主線程也可以獲取
new Thread(new Runnable() { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + "...aaaaaaaaaaaaaaaaaaaaa"); } } }).start(); new Thread(new Runnable() { public void run() { for(int i = 0; i < 1000; i++) { System.out.println(Thread.currentThread().getName() + "...bb"); } } }).start(); Thread.currentThread().setName("我是主線程"); //獲取主函數(shù)線程的引用,并改名字 System.out.println(Thread.currentThread().getName()); //獲取主函數(shù)線程的引用,并獲取名字
24.11_多線程(休眠線程)(掌握)
-
Thread.sleep(毫秒,納秒), 控制當前線程休眠若干毫秒1秒= 1000毫秒 1秒 = 1000 * 1000 * 1000納秒 1000000000
new Thread() { public void run() { for(int i = 0; i < 10; i++) { System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start(); new Thread() { public void run() { for(int i = 0; i < 10; i++) { System.out.println(getName() + "...bb"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }.start();
24.12_多線程(守護線程)(掌握)
- setDaemon(boolean), 設置一個線程為守護線程, 該線程不會單獨執(zhí)行, 當其他非守護線程都執(zhí)行結束后, 自動退出【守護線程 也可以守護 main線程】
Thread t1 = new Thread() { public void run() { for(int i = 0; i < 50; i++) { System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread t2 = new Thread() { public void run() { for(int i = 0; i < 5; i++) { System.out.println(getName() + "...bb"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }; t1.setDaemon(true); //將t1設置為守護線程 t1.start(); t2.start();
24.13_多線程(加入線程)(掌握)
- join(), 當前線程暫停, 等待指定的線程執(zhí)行結束后, 當前線程再繼續(xù)
- join(int), 可以等待指定的毫秒之后繼續(xù)
final Thread t1 = new Thread() { public void run() { for(int i = 0; i < 50; i++) { System.out.println(getName() + "...aaaaaaaaaaaaaaaaaaaaaa"); try { Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } } }; Thread t2 = new Thread() { public void run() { for(int i = 0; i < 50; i++) { if(i == 2) { try { t1.join(); //插隊,加入 //t1.join(30); //加入,有固定的時間,過了固定時間,繼續(xù)交替執(zhí)行 Thread.sleep(10); } catch (InterruptedException e) { e.printStackTrace(); } } System.out.println(getName() + "...bb"); } } }; t1.start(); t2.start();
24.14_多線程(禮讓線程)(了解)
- yield()讓出cpu
- 建議性的
24.15_多線程(設置線程的優(yōu)先級)(了解)
- setPriority(int)設置線程的優(yōu)先級掏秩,參數(shù)越大優(yōu)先級越高。
- 優(yōu)先級取值 1 到 10 荆姆,數(shù)值越大蒙幻,優(yōu)先級越高
- 建議性的
24.16_多線程(同步代碼塊)(掌握)
- 1.什么情況下需要同步
- 當多線程并發(fā), 有多段代碼同時執(zhí)行時, 我們希望某一段代碼執(zhí)行的過程中CPU不要切換到其他線程工作. 這時就需要同步.
- 如果兩段代碼是同步的, 那么同一時間只能執(zhí)行一段, 在一段代碼沒執(zhí)行結束之前, 不會執(zhí)行另外一段代碼.
- 2.同步代碼塊
使用synchronized關鍵字加上一個鎖對象來定義一段代碼, 這就叫同步代碼塊
-
多個同步代碼塊如果使用相同的鎖對象, 那么他們就是同步的
class Printer { Demo d = new Demo(); public static void print1() { //鎖對象可以是任意對象,但是被鎖的代碼需要保證是同一把鎖,不能用匿名對象 synchronized(d){ System.out.print("我"); System.out.print("要"); System.out.print("賺"); System.out.print("大"); System.out.print("錢"); System.out.print("\r\n"); } } public static void print2() { synchronized(d){ System.out.print("努"); System.out.print("力"); System.out.print("學"); System.out.print("習"); System.out.print("\r\n"); } } }
24.17_多線程(同步方法)(掌握)
-
使用synchronized關鍵字修飾一個方法, 該方法中所有的代碼都是同步的
class Printer { public static void print1() { //鎖對象可以是任意對象,但是被鎖的代碼需要保證是同一把鎖,不能用匿名對象 synchronized(Printer.class){ System.out.print("I"); System.out.print("T"); System.out.print("程"); System.out.print("序"); System.out.print("員"); System.out.print("\r\n"); } } /* * 非靜態(tài)同步函數(shù)的鎖是:this * 靜態(tài)的同步函數(shù)的鎖是:字節(jié)碼對象 */ public static synchronized void print2() { System.out.print("杰"); System.out.print("普"); System.out.print("軟"); System.out.print("件"); System.out.print("\r\n"); } }
24.18_多線程(線程安全問題)(掌握)
多線程并發(fā)操作同一數(shù)據(jù)時, 就有可能出現(xiàn)線程安全問題
-
使用同步技術可以解決這種問題, 把操作數(shù)據(jù)的代碼進行同步, 不要多個線程一起操作
public class Demo2_Synchronized { /** * @param args * 需求:鐵路售票,一共100張,通過四個窗口賣完. */ public static void main(String[] args) { TicketsSeller t1 = new TicketsSeller(); TicketsSeller t2 = new TicketsSeller(); TicketsSeller t3 = new TicketsSeller(); TicketsSeller t4 = new TicketsSeller(); t1.setName("窗口1"); t2.setName("窗口2"); t3.setName("窗口3"); t4.setName("窗口4"); t1.start(); t2.start(); t3.start(); t4.start(); } } class TicketsSeller extends Thread { private static int tickets = 100; static Object obj = new Object(); public TicketsSeller() { super(); } public TicketsSeller(String name) { super(name); } public void run() { while(true) { synchronized(obj) { if(tickets <= 0) break; try { Thread.sleep(10);//線程1睡,線程2睡,線程3睡,線程4睡 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(getName() + "...這是第" + tickets-- + "號票"); } } } }
24.19_多線程(火車站賣票的例子用實現(xiàn)Runnable接口)(掌握)
- 作業(yè)
24.20_多線程(死鎖)(了解)
- 多線程同步的時候, 如果同步代碼嵌套, 使用相同鎖, 就有可能出現(xiàn)死鎖
-
盡量不要嵌套使用
private static String s1 = "筷子左"; private static String s2 = "筷子右"; public static void main(String[] args) { new Thread() { public void run() { while(true) { synchronized(s1) { System.out.println(getName() + "...拿到" + s1 + "等待" + s2); synchronized(s2) { System.out.println(getName() + "...拿到" + s2 + "開吃"); } } } } }.start(); new Thread() { public void run() { while(true) { synchronized(s2) { System.out.println(getName() + "...拿到" + s2 + "等待" + s1); synchronized(s1) { System.out.println(getName() + "...拿到" + s1 + "開吃"); } } } } }.start(); }
-
24.21_多線程(以前的線程安全的類回顧)(掌握)
- A:回顧以前說過的線程安全問題
- 看源碼:Vector,StringBuffer,Hashtable Collections.synchroinzedXxx(xxx)
- Vector是線程安全的,ArrayList是線程不安全的
- StringBuffer是線程安全的,StringBuilder是線程不安全的
- Hashtable是線程安全的,HashMap是線程不安全的
25.01_多線程(兩個線程間的通信)(掌握)
- 1.什么時候需要通信
- 多個線程并發(fā)執(zhí)行時, 在默認情況下CPU是隨機切換線程的
- 如果我們希望他們有規(guī)律的執(zhí)行, 就可以使用通信, 例如每個線程執(zhí)行一次打印
- 2.怎么通信
- 如果希望線程等待, 就調用wait()【先釋放鎖,再阻塞】
- 如果希望喚醒等待的線程, 就調用notify();【被喚醒胆筒,先轉入運行邮破,再競爭鎖,獲取鎖以后仆救,才可以往下運行】
- 這兩個方法必須在同步代碼中執(zhí)行, 并且使用【同步鎖對象】來調用
25.02_多線程(三個或三個以上間的線程通信)
- 多個線程通信的問題
- notify()方法是隨機喚醒一個線程
- notifyAll()方法是喚醒所有線程
- JDK5之前無法喚醒指定的一個線程
- 如果多個線程之間通信, 需要使用notifyAll()通知所有線程, 用while來反復判斷條件
- 在同步代碼塊中抒和,使用哪個對象鎖,就使用該對象調用wait方法
- 為什么wait方法和notify方法定義在Object類中彤蔽?
- 我們使用鎖對象調用上述方法摧莽,而鎖對象可以是任意對象,所以定義到Object類中
- sleep方法和wait方法有什么區(qū)別顿痪?
- sleep方法必須傳入?yún)?shù)值镊辕,即一個時間值油够,時間到了自動醒來
- wait方法中參數(shù)可有可無,有參表示過了參數(shù)時間后進入等待征懈,否則直接等待
- sleep方法在同步函數(shù)或同步代碼塊中石咬,不釋放鎖
- wait方法在同步函數(shù)或同步代碼塊中,釋放鎖
25.03_多線程(JDK1.5的新特性互斥鎖)(掌握)
- 1.同步
- 使用ReentrantLock類的lock()和unlock()方法進行同步
- 類似synchronized
- 2.通信
- 使用ReentrantLock類的newCondition()方法可以獲取Condition對象
- 需要等待的時候使用Condition的await()方法, 喚醒的時候用signal()方法
- 不同的線程使用不同的Condition, 這樣就能區(qū)分喚醒的時候找哪個線程了
25.04_多線程(線程組的概述和使用)(了解)
-
A:線程組概述
- Java中使用ThreadGroup來表示線程組卖哎,它可以對一批線程進行分類管理鬼悠,Java允許程序直接對線程組進行控制。
- 默認情況下亏娜,所有的線程都屬于【主線程組】
- public final ThreadGroup getThreadGroup()//通過線程對象獲取他所屬于的組
- public final String getName()//通過線程組對象獲取他組的名字
- 我們也可以給線程設置分組
- 1,ThreadGroup(String name) 創(chuàng)建線程組對象并給其賦值名字
- 2,創(chuàng)建線程對象
- 3,Thread(ThreadGroup group, Runnable target, String name)
- 4,設置整組的優(yōu)先級或者守護線程
- B:案例演示
- 線程組的使用,默認是主線程組
-
MyRunnable mr = new MyRunnable(); Thread t1 = new Thread(mr, "張三"); Thread t2 = new Thread(mr, "李四"); //獲取線程組 // 線程類里面的方法:public final ThreadGroup getThreadGroup() ThreadGroup tg1 = t1.getThreadGroup(); ThreadGroup tg2 = t2.getThreadGroup(); // 線程組里面的方法:public final String getName() String name1 = tg1.getName(); String name2 = tg2.getName(); System.out.println(name1); System.out.println(name2); // 通過結果我們知道了:線程默認情況下屬于main線程組 // 通過下面的測試焕窝,你應該能夠看到,默任情況下维贺,所有的線程都屬于同一個組 System.out.println(Thread.currentThread().getThreadGroup().getName());
- 自己設定線程組
// ThreadGroup(String name) ThreadGroup tg = new ThreadGroup("這是一個新的組"); MyRunnable mr = new MyRunnable(); // Thread(ThreadGroup group, Runnable target, String name) Thread t1 = new Thread(tg, mr, "張三"); Thread t2 = new Thread(tg, mr, "李四"); System.out.println(t1.getThreadGroup().getName()); System.out.println(t2.getThreadGroup().getName()); //通過組名稱設置后臺線程袜啃,表示該組的線程都是后臺線程 tg.setDaemon(true);
25.05_多線程(線程的五種狀態(tài))(掌握)
- 看圖說話
- 新建,就緒,運行,阻塞,死亡
25.06_多線程(線程池的概述和使用)(了解)
- A:線程池概述
- 程序啟動一個新線程成本是比較高的,因為它涉及到要與操作系統(tǒng)進行交互幸缕。而使用線程池可以很好的提高性能群发,尤其是當程序中要創(chuàng)建大量生存期很短的線程時,更應該考慮使用線程池发乔。線程池里的每一個線程代碼結束后熟妓,并不會死亡,而是再次回到線程池中成為空閑狀態(tài)栏尚,等待下一個對象來使用起愈。在JDK5之前,我們必須手動實現(xiàn)自己的線程池译仗,從JDK5開始抬虽,Java內(nèi)置支持線程池
- B:內(nèi)置線程池的使用概述
- JDK5新增了一個Executors工廠類來產(chǎn)生線程池,有如下幾個方法
- public static ExecutorService newFixedThreadPool(int nThreads)
- public static ExecutorService newSingleThreadExecutor()
- 這些方法的返回值是ExecutorService對象纵菌,該對象表示一個線程池阐污,可以執(zhí)行Runnable對象或者Callable對象代表的線程。它提供了如下方法
- Future<?> submit(Runnable task)
- <T> Future<T> submit(Callable<T> task)
- 使用步驟:
- 創(chuàng)建線程池對象
- 創(chuàng)建Runnable實例
- 提交Runnable實例
- 關閉線程池
- C:案例演示
- 提交的是Runnable
- JDK5新增了一個Executors工廠類來產(chǎn)生線程池,有如下幾個方法
// public static ExecutorService newFixedThreadPool(int nThreads) ExecutorService pool = Executors.newFixedThreadPool(2); // 可以執(zhí)行Runnable對象或者Callable對象代表的線程 pool.submit(new MyRunnable()); pool.submit(new MyRunnable()); //結束線程池 pool.shutdown();
25.07_多線程(多線程程序實現(xiàn)的方式3)(了解)
- 提交的是Callable
// 創(chuàng)建線程池對象 ExecutorService pool = Executors.newFixedThreadPool(2); // 可以執(zhí)行Runnable對象或者Callable對象代表的線程 Future<Integer> f1 = pool.submit(new MyCallable(100)); Future<Integer> f2 = pool.submit(new MyCallable(200)); // V get() Integer i1 = f1.get(); Integer i2 = f2.get(); System.out.println(i1); System.out.println(i2); // 結束 pool.shutdown(); public class MyCallable implements Callable<Integer> { private int number; public MyCallable(int number) { this.number = number; } @Override public Integer call() throws Exception { int sum = 0; for (int x = 1; x <= number; x++) { sum += x; } return sum; } }
- 多線程程序實現(xiàn)的方式3的好處和弊端
-
好處:
- 可以有返回值
- 可以拋出異常
-
弊端:
- 代碼比較復雜咱圆,所以一般不用
-
25.08_設計模式(簡單工廠模式概述和使用)(了解)
- A:簡單工廠模式概述
- 又叫靜態(tài)工廠方法模式笛辟,它定義一個具體的工廠類負責創(chuàng)建一些類的實例
- B:優(yōu)點
- 客戶端不需要在負責對象的創(chuàng)建,從而明確了各個類的職責
- C:缺點
- 這個靜態(tài)工廠類負責所有對象的創(chuàng)建序苏,如果有新的對象增加手幢,或者某些對象的創(chuàng)建方式不同,就需要不斷的修改工廠類忱详,不利于后期的維護
- D:案例演示
- 動物抽象類:public abstract Animal { public abstract void eat(); }
- 具體狗類:public class Dog extends Animal {}
- 具體貓類:public class Cat extends Animal {}
- 開始围来,在測試類中每個具體的內(nèi)容自己創(chuàng)建對象,但是,創(chuàng)建對象的工作如果比較麻煩监透,就需要有人專門做這個事情钦铁,所以就知道了一個專門的類來創(chuàng)建對象。
public class AnimalFactory { private AnimalFactory(){} //public static Dog createDog() {return new Dog();} //public static Cat createCat() {return new Cat();} //改進 public static Animal createAnimal(String animalName) { if(“dog”.equals(animalName)) {} else if(“cat”.equals(animale)) { }else { return null; } } }
25.09_設計模式(工廠方法模式的概述和使用)(了解)
- A:工廠方法模式概述
- 工廠方法模式中抽象工廠類負責定義創(chuàng)建對象的接口才漆,具體對象的創(chuàng)建工作由繼承抽象工廠的具體類實現(xiàn)。
- 普通工廠模式【一個方法生產(chǎn)多種對象】
- 多個工廠模式【多個方法各自生產(chǎn)對象】
- 靜態(tài)工廠模式【方法設置static】
- 抽象工廠模式【將工廠抽象得到 抽象工廠基類】
- B:抽象工廠模式優(yōu)點
- 客戶端不需要在負責對象的創(chuàng)建佛点,從而明確了各個類的職責醇滥,如果有新的對象增加,只需要增加一個具體的類和具體的工廠類即可超营,不影響已有的代碼鸳玩,后期維護容易,增強了系統(tǒng)的擴展性
- C:缺點
- 需要額外的編寫代碼演闭,增加了工作量
- D:案例演示
動物抽象類:public abstract Animal { public abstract void eat(); } 工廠接口:public interface Factory {public abstract Animal createAnimal();} 具體狗類:public class Dog extends Animal {} 具體貓類:public class Cat extends Animal {} 開始不跟,在測試類中每個具體的內(nèi)容自己創(chuàng)建對象,但是米碰,創(chuàng)建對象的工作如果比較麻煩窝革,就需要有人專門做這個事情,所以就知道了一個專門的類來創(chuàng)建對象吕座。發(fā)現(xiàn)每次修改代碼太麻煩虐译,用工廠方法改進,針對每一個具體的實現(xiàn)提供一個具體工廠吴趴。 狗工廠:public class DogFactory implements Factory { public Animal createAnimal() {…} } 貓工廠:public class CatFactory implements Factory { public Animal createAnimal() {…} }
25.10_多線程(單例設計模式)(掌握)
單例設計模式:保證類在內(nèi)存中只有一個對象漆诽。
-
如何保證類在內(nèi)存中只有一個對象呢?
- (1)控制類的創(chuàng)建锣枝,不讓其他類來創(chuàng)建本類的對象厢拭。private
- (2)在本類中定義一個本類的對象。Singleton s;
- (3)提供公共的訪問方式撇叁。 public static Singleton getInstance(){return s}
-
單例寫法兩種:
- (1)餓漢式 開發(fā)用這種方式供鸠。
//餓漢式 class Singleton { //1,私有構造函數(shù) private Singleton(){} //2,創(chuàng)建本類對象 private static Singleton s = new Singleton(); //3,對外提供公共的訪問方法 public static Singleton getInstance() { return s; } public static void print() { System.out.println("11111111111"); } }
- (2)懶漢式 面試寫這種方式。多線程的問題陨闹?
//懶漢式,單例的延遲加載模式 class Singleton { //1,私有構造函數(shù) private Singleton(){} //2,聲明一個本類的引用 private static Singleton s; //3,對外提供公共的訪問方法 public static Singleton getInstance() { if(s == null) //線程1,線程2 s = new Singleton(); return s; } public static void print() { System.out.println("11111111111"); } }
- (3)第三種格式
class Singleton { private Singleton() {} public static final Singleton s = new Singleton();//final是最終的意思,被final修飾的變量不可以被更改 }
25.11_多線程(Runtime類)
- Runtime類是一個單例類
Runtime r = Runtime.getRuntime(); //r.exec("shutdown -s -t 300"); //300秒后關機 r.exec("shutdown -a"); //取消關機
25.12_多線程(Timer)(掌握)
-
Timer類:計時器
public class Demo5_Timer { /** * @param args * 計時器 * @throws InterruptedException */ public static void main(String[] args) throws InterruptedException { Timer t = new Timer(); t.schedule(new MyTimerTask(), new Date(114,9,15,10,54,20),3000); while(true) { System.out.println(new Date()); Thread.sleep(1000); } } } class MyTimerTask extends TimerTask { @Override public void run() { System.out.println("起床背英語單詞"); } }
25.13_GUI(如何創(chuàng)建一個窗口并顯示)
- Graphical User Interface(圖形用戶接口)回季。
Frame f = new Frame(“my window”); f.setLayout(new FlowLayout());//設置布局管理器 f.setSize(500,400);//設置窗體大小 f.setLocation(300,200);//設置窗體出現(xiàn)在屏幕的位置 f.setIconImage(Toolkit.getDefaultToolkit().createImage("qq.png")); f.setVisible(true);
25.14_GUI(布局管理器)
- FlowLayout(流式布局管理器)
- 從左到右的順序排列。
- Panel默認的布局管理器正林。
- BorderLayout(邊界布局管理器)
- 東泡一,南,西觅廓,北鼻忠,中(填充所有)
- Frame默認的布局管理器。
- GridLayout(網(wǎng)格布局管理器)
- 規(guī)則的矩陣
- CardLayout(卡片布局管理器)
- 選項卡eclipse編輯區(qū)
- GridBagLayout(網(wǎng)格包布局管理器)
- 非規(guī)則的矩陣(計算器應用)
25.15_GUI(窗體監(jiān)聽)
Frame f = new Frame("我的窗體");
//事件源是窗體,把監(jiān)聽器注冊到事件源上
//事件對象傳遞給監(jiān)聽器
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
//退出虛擬機,關閉窗口
System.exit(0);
}
});
25.16_GUI(鼠標監(jiān)聽)
- 組件.addMouseListener(new MouseAdapter(){ 重寫方法; });
25.17_GUI(鍵盤監(jiān)聽和鍵盤事件)
- 組件.addKeyListener();
- KeyEvent: getKeyCode() VK_SPACE
25.18_GUI(動作監(jiān)聽)
- 默認就是空格鍵 鼠標左鍵
- 應用場景: 點擊左鍵、空格 視頻暫停播放
- 組件.addActionListener(new ActionListener(){ ... });
25.19_設計模式(適配器設計模式)(掌握)
- a.什么是適配器
- 在使用監(jiān)聽器的時候, 需要定義一個類事件監(jiān)聽器接口.
- 通常接口中有多個方法, 而程序中不一定所有的都用到, 但又必須重寫, 這很繁瑣.
- 適配器簡化了這些操作, 我們定義監(jiān)聽器時只要繼承適配器, 然后重寫需要的方法即可.
- b.適配器原理
- 適配器就是一個類, 實現(xiàn)了監(jiān)聽器接口, 所有抽象方法都重寫了, 但是方法全是空的.
- 適配器類需要定義成抽象的,因為創(chuàng)建該類對象,調用空方法是沒有意義的
- 目的就是為了簡化程序員的操作, 定義監(jiān)聽器時繼承適配器, 只重寫需要的方法就可以了.
25.20_GUI(需要知道的)
- 事件處理
- 事件: 用戶的一個操作
- 事件源: 被操作的組件
- 監(jiān)聽器: 一個自定義類的對象, 實現(xiàn)了監(jiān)聽器接口, 包含事件處理方法,把監(jiān)聽器添加在事件源上, 當事件發(fā)生的時候虛擬機就會自動調用監(jiān)聽器中的事件處理方法
25.21_day25總結
把今天的知識點總結一遍帖蔓。