單選題 Thread類中能運行線程體的方法是B.run( )。start( )方法會啟動一個新的線程,init( )方法是構造器的一部分,resume( )方法是恢復一個暫停的線程。 如果要把容器空間分成東、西、南、北、中五個區域,應採用的佈局是D.BorderLayout。BorderLayout ...
單選題
Thread類中能運行線程體的方法是B.run( )。start( )方法會啟動一個新的線程,init( )方法是構造器的一部分,resume( )方法是恢復一個暫停的線程。
如果要把容器空間分成東、西、南、北、中五個區域,應採用的佈局是D.BorderLayout。BorderLayout類可以將容器分為五個區域:EAST,WEST,SOUTH,NORTH和CENTER。每個區域只能放置一個組件,如果放置多個組件,只有最後一個組件可見。
能讓線程從阻塞狀態恢復到就緒狀態的方法是B.resume()。init()方法是構造器的一部分,start()方法會啟動一個新的線程,run()方法是線程體的執行部分。
如果lianxi.txt不存在,則A.程式會自動創建該文件。FileOutputStream類的構造方法可以接受一個字元串參數,表示要寫入的文件名。如果該文件不存在,會自動創建一個新的文件。如果該文件已存在,會覆蓋原有的內容。
關於繼承的說法正確的是D.子類將繼承父類非私有屬性和方法。繼承是一種面向對象的特征,它允許子類獲得父類的屬性和方法。私有屬性和方法是父類的內部實現,不會被子類繼承。公有和受保護的屬性和方法可以被子類繼承,但是受保護的屬性和方法只能在子類內部訪問,不能在外部訪問。
下麵正確的創建Socket的語句為A.Socket b=new Socket(” 130.3.4.5”,80):。Socket類的構造方法可以接受一個字元串參數和一個整數參數,分別表示要連接的伺服器的IP地址和埠號。ServerSocket類是用於創建伺服器端的套接字,它不能用來創建客戶端的套接字。ServerSocket類的構造方法只接受一個整數參數,表示伺服器端的埠號。
為實現線程之間的通信,需要使用下列哪種流合適? C.管道流 (PipedStream)。管道流是一種特殊的流,它可以在兩個線程之間傳輸數據。一個線程可以通過PipedOutputStream向管道中寫入數據,另一個線程可以通過PipedInputStream從管道中讀取數據。過濾流,緩存流和文件流都不適合用於線程之間的通信,它們都是用於處理其他類型的數據源或目的地的流。
JPanel預設的佈局管理器是A. FlowLayout。FlowLayout類是一種簡單的佈局管理器,它可以將組件按照從左到右,從上到下的順序排列在容器中。如果容器的大小不足以顯示所有的組件,FlowLayout會自動換行。GroupLayout,GridLayout和BorderLayout都不是JPanel的預設佈局管理器,但是可以通過setLayout方法來設置。
下麵哪些類用於實現TCP/IP客戶和伺服器? D.Socket, ServerSocket。Socket類和ServerSocket類是用於實現TCP/IP協議的客戶端和伺服器端的套接字。Socket類可以創建一個客戶端的套接字,用於連接到指定的伺服器。ServerSocket類可以創建一個伺服器端的套接字,用於監聽客戶端的連接請求。DatagramPacket類和DatagramSocket類是用於實現UDP協議的數據包和套接字。UDP協議是一種無連接的協議,它不保證數據的可靠性和順序性。
介面MouseMotionListener用於監聽組件上的滑鼠移動事件,它包括兩個方法:mouseMoved(MouseEvent e)和mouseDragged(MouseEvent e)。在以下供選擇的方法中,屬於介面MouseMotionListener的方法是B. mouseMoved( )。MouseMotionListener介面是用於接收滑鼠移動事件的監聽器介面,它有兩個抽象方法:mouseDragged( MouseEvent e)和mouseMoved( MouseEvent e)。mouseDragged( )方法是當滑鼠按下並拖動時觸發,mouseMoved( )方法是當滑鼠移動但沒有按下時觸發。 mouseEntered( )方法和mouseExited( )方法是屬於MouseListener介面的方法,它們是當滑鼠進入或離開組件時觸發。mouseReleased( )方法也是屬於MouseListener介面的方法,它是當滑鼠釋放時觸發。
mouseEntered和mouseMoved的區別如下:
- mouseEntered是MouseListener介面中的方法,它在滑鼠進入某個組件的區域時觸發。
- mouseMoved是MouseMotionListener介面中的方法,它在滑鼠在某個組件上移動時觸發。
- mouseEntered不支持事件冒泡,也就是說,如果滑鼠從一個組件的子元素進入到該組件,不會觸發mouseEntered事件。
- mouseMoved支持事件冒泡,也就是說,如果滑鼠在一個組件的子元素上移動,會觸發該組件的mouseMoved事件。
聲明並創建一個按鈕對象b,應該使用的語句是C.JButton b=new JButton()。JButton類是用於創建按鈕的類,它是javax.swing包中的一個類。要聲明並創建一個按鈕對象,需要使用JButton類的無參構造方法。button類是java.awt包中的一個類,它是一個舊的按鈕類,不推薦使用。b.setLabel(“確定”)是一個方法調用,不是一個聲明語句。JButton b=new b()是一個錯誤的語句,因為b不是一個類名。
容器被重新設置大小後,C.FlowLayout佈局管理器的容器中的組件大小不隨容器大小的變化而改變。FlowLayout類是一種簡單的佈局管理器,它可以將組件按照從左到右,從上到下的順序排列在容器中。如果容器的大小不足以顯示所有的組件,FlowLayout會自動換行。但是,FlowLayout不會改變組件的大小,只會改變組件的位置。BorderLayout類,CardLayout類和GridLayout類都會根據容器的大小來調整組件的大小和位置。
下麵通常用來對對象加鎖,並使得對對象的訪問是排他的關鍵字是B. synchronized。synchronized關鍵字可以用來修飾方法或者代碼塊,表示該方法或者代碼塊是同步的,也就是說,同一時刻只能有一個線程執行該方法或者代碼塊。這樣可以保證對對象的訪問是互斥的,避免數據的不一致性。transient關鍵字可以用來修飾屬性,表示該屬性不會被序列化。static關鍵字可以用來修飾屬性或者方法,表示該屬性或者方法是屬於類的,而不是屬於對象的。serialize不是一個關鍵字,而是一個介面,表示一個類的對象可以被序列化。
public Color(int r,int g,int b,int alpha): 用指定的紅色分量r、綠色分量g、藍色分量b的值構造一個Color對象,其中r、g、b均為D.0-255之間的一個整數。Color類是用於封裝顏色的類,它有多個構造方法,其中一個是接受四個整數參數的構造方法,分別表示紅色分量,綠色分量,藍色分量和透明度分量。這四個參數的取值範圍都是0-255,其中0表示最小值,255表示最大值。
假設正在為應用系統設計一個Java圖形用戶界面 (GUI),要求能輸入多行文本信息,下列組件中最能滿足這個要求的是D.TextArea。TextArea類是用於創建多行文本輸入框的類,它可以讓用戶輸入和編輯多行的文本信息。Label類是用於創建標簽的類,它只能顯示一行的文本信息,不能讓用戶輸入。Checkbox類是用於創建覆選框的類,它可以讓用戶選擇或取消選擇一個選項,但不能輸入文本。TextField類是用於創建單行文本輸入框的類,它只能讓用戶輸入和編輯一行的文本信息。
如果容器組件p的佈局是BorderLayout,則在p的下邊中添加一個按鈕b,應該使用的語句是A. p.add(b,“South”)。BorderLayout類是一種佈局管理器,它可以將容器分為五個區域:EAST,WEST,SOUTH,NORTH和CENTER。每個區域只能放置一個組件,如果放置多個組件,只有最後一個組件可見。要在容器的某個區域添加一個組件,需要使用容器的add方法,並指定區域的名稱。例如,p.add(b,“South”)表示在p的南邊區域添加一個按鈕b。B. b.add(p,“North”)是錯誤的語句,因為不能將容器添加到按鈕中。C. p.add(b)是不完整的語句,因為沒有指定區域的名稱。D.p.add(b,“North”)是正確的語句,但是它表示在p的上邊中添加一個按鈕b,而不是下邊。
線程的哪一個狀態已經具備了運行條件:A.就緒狀態。
A.就緒狀態。就緒狀態是指線程已經創建並且獲取了除CPU資源之外的所有資源,只要獲得CPU資源,就可以立即執行。就緒狀態的線程是由調度器根據一定的演算法來選擇執行的。B.死亡狀態是指線程已經結束或者被終止,不再具備運行條件。C.新建狀態是指線程剛剛被創建,還沒有啟動,也沒有獲取任何資源,不具備運行條件。D.死鎖狀態是指線程在等待某個資源,而該資源又被其他線程占用,導致線程無法繼續執行,也不具備運行條件。
在異常處理中,如釋放資源、關閉文件、關閉資料庫等由A.finally子句來完成。finally子句是異常處理中的一個可選部分,它用於執行一些必須的清理操作,無論是否發生異常,finally子句都會被執行。try子句是異常處理中的一個必須部分,它用於包含可能發生異常的代碼。catch子句是異常處理中的一個可選部分,它用於捕獲和處理特定類型的異常。throw子句是用於拋出異常的語句,它不屬於異常處理的結構。
在Java中,如果要讓正在運行的線程進入睡眠狀態,可以調用線程的C.sleep()方法。這個方法是Thread類的一個靜態方法,它可以讓當前線程暫時放棄CPU的調度權,但不會釋放鎖資源。sleep()方法有兩個重載版本,一個是接受一個long類型的參數,表示睡眠的毫秒數;另一個是接受一個long類型和一個int類型的參數,表示睡眠的毫秒數和納秒數。
構造函數是一種特殊的成員函數,它的作用是在創建對象時對對象的數據成員進行初始化。構造函數的特點有以下幾點:
- 構造函數的名字與類名相同,可以有參數,但不能有返回值(連void也不行)。
- 構造函數是在實例化對象時自動執行的,不需要用戶手動調用。
- 構造函數可以有多個,形成重載關係,根據傳入的參數類型和個數來調用不同的構造函數。
- 構造函數可以有預設參數,這樣可以在實例化對象時不傳入參數或只傳入部分參數。
- 如果沒有定義構造函數,系統會生成一個預設的無參構造函數,不做任何初始化工作。如果定義了構造函數,系統就不再生成預設的無參構造函數。
舉個例子,假設有一個類Box,它有三個數據成員:height, width, length。我們可以定義以下幾種構造函數:
//無參構造函數 Box() { height = 0; width = 0; length = 0; } //帶三個參數的構造函數 Box(int h, int w, int l) { height = h; width = w; length = l; } //帶一個參數的構造函數 Box(int x) { height = x; width = x; length = x; } //帶預設參數的構造函數 Box(int h = 10, int w = 10, int l = 10) { height = h; width = w; length = l; }
那麼我們可以用以下幾種方式來實例化對象:
Box b1; //調用無參構造函數或帶預設參數的構造函數 Box b2(5); //調用帶一個參數的構造函數或帶預設參數的構造函數 Box b3(5, 10, 15); //調用帶三個參數的構造函數或帶預設參數的構造函數 Box b4(5, 10); //調用帶預設參數的構造函數
這樣就可以根據不同的需求來初始化對象的數據成員了。
多選題
Java分支結構
Java分支結構之多重if (10.0分)
Java分支結構之Switch (10.0分)
第1關:Java分支結構之多重if
任務描述
本小節需要你實現一個星級成績評定系統,效果如下:
相關知識
若要完成本小節的任務,需要你先瞭解多重If語句相關知識。
多重If語句
在條件 1 不滿足的情況下,才會進行條件 2 的判斷;當前面的條件均不成立時,才會執行 else 塊內的代碼,例如:如果一個人年齡介於 35歲至 60 歲之間,就是“中年”;如果年齡介於 18 歲至 35 歲之間,則是“青年”; 18 歲以下則是“少年”
如下:
- if(<條件1>){
- <條件1成立執行的代碼>
- }elseif(<條件2>){
- <條件2成立執行的代碼>
- }elseif(<條件3>){
- <條件3成立執行的代碼>
- }else{
- <以上條件都不成立執行的代碼>
- }
執行過程:
- int age =37;
- if(age <18){
- System.out.println("少年");
- }elseif(age >=18&& age <35){
- System.out.println("青年");
- }elseif(age >=35&& age <60){
- System.out.println("中年");
- }else{
- System.out.println("老年");
- }
編程要求
在start-end區域在Begin-End區域編寫一個星級成績評定系統,規則如下:
- 90分及以上:五星成績。
- 80-90分(包括80分,不包含90分): 四星成績。
- 70-80分(包括70分,不包含80分):: 三星成績。
- 60-70分(包括60分,不包含70分):: 倆星成績。
- 60分以下(不包含60分)::無星成績。
效果圖如下:
測試說明
我會對你編寫的程式測試五次,不要偷懶哦!
開始吧,騷年!
package step3; import java.util.Scanner; public class HelloStep3 { public static void main(String[] args) { System.out.println("星級成績評定系統"); System.out.println("請輸入成績:"); Scanner sc = new Scanner(System.in); /******start******/ // 讀取用戶輸入的成績 int score=sc.nextInt(); // 判斷成績是否在90-100之間,如果是,輸出五星成績 if((score>=90)&&(score<=100)){ System.out.println("*****五星成績"); } // 判斷成績是否在80-90之間,如果是,輸出四星成績 else if((score>=80)&&(score<90)){ System.out.println("****四星成績"); } // 判斷成績是否在70-80之間,如果是,輸出三星成績 else if((score>=70)&&(score<80)){ System.out.println("***三星成績"); } // 判斷成績是否在60-70之間,如果是,輸出倆星成績 else if((score>=60)&&(score<70)){ System.out.println("**倆星成績"); } // 判斷成績是否在0-60之間,如果是,輸出無星成績 else if((score>=0)&&(score<60)){ System.out.println("無星成績"); } /******end******/ } }
Java高級特性 - 多線程基礎(3)線程同步
使用synchronized關鍵字同步線程 (10.0分)
第1關:使用synchronized關鍵字同步線程
任務描述
本關任務:使右側代碼中的insert方法在同一時刻只有一個線程能訪問。
相關知識
為了完成本關任務,你需要掌握:
1.併發編程什麼時候會出現安全問題;
2.怎麼解決線程安全問題;
3.synchronized關鍵字。
併發編程什麼時候會出現安全問題
在單線程的時候是不會出現安全問題的,不過在多線程的情況下就很有可能出現,比如說:多個線程同時訪問同一個共用資源,多個線程同時向資料庫插入數據,這些時候如果我們不做任何處理,就很有可能出現數據實際結果與我們預期的結果不符合的情況。
現在有兩個線程同時獲取用戶輸入的數據,然後將數據插入到同一張表中,要求不能出現重覆的數據。
我們必然要在插入數據的時候進行如下操作:
- 檢查資料庫中是否存在該數據;
- 如果存在則不插入,否則插入。
現在有兩個線程ThreadA和ThreadB來對資料庫進行操作,當某個時刻,線程A和B同時讀取到了數據X,這個時候他們都去資料庫驗證X是否存在,得到的結果都是不存在,然後A、B線程都向資料庫插入了X數據,這個時候資料庫中出現了兩條X數據,還是出現了數據重覆。
這個就是線程安全問題,多個線程同時訪問一個資源時,會導致程式運行結果並不是想看到的結果。
這裡面,這個資源被稱為:臨界資源(也可以叫共用資源)。
當多個線程同時訪問臨界資源(一個對象,對象中的屬性,一個文件,一個資料庫等等)時,就有可能產生線程安全問題。
當多個線程執行一個方法時,方法內部的局部變數並不是臨界資源,因為方法是在棧上執行的,而Java棧是線程私有的,因此不會產生線程安全問題。
如何解決線程安全問題
怎麼解決線程的安全問題呢?
基本上所有解決線程安全問題的方式都是採用“序列化臨界資源訪問”的方式,即在同一時刻只有一個線程操作臨界資源,操作完了才能讓其他線程進行操作,也稱作同步互斥訪問。
在Java中一般採用synchronized和Lock來實現同步互斥訪問。
synchronized關鍵字
首先我們先來瞭解一下互斥鎖,互斥鎖:就是能達到互斥訪問目的的鎖。
如果對一個變數加上互斥鎖,那麼在同一時刻,該變數只能有一個線程能訪問,即當一個線程訪問臨界資源時,其他線程只能等待。
在Java中,每一個對象都有一個鎖標記(monitor),也被稱為監視器,當多個線程訪問對象時,只有獲取了對象的鎖才能訪問。
在我們編寫代碼的時候,可以使用synchronized修飾對象的方法或者代碼塊,當某個線程訪問這個對象synchronized方法或者代碼塊時,就獲取到了這個對象的鎖,這個時候其他對象是不能訪問的,只能等待獲取到鎖的這個線程執行完該方法或者代碼塊之後,才能執行該對象的方法。
我們來看個示例進一步理解synchronized關鍵字:
- publicclassExample{
- publicstaticvoid main(String[] args) {
- finalInsertData insertData =newInsertData();
- newThread(){
- publicvoid run(){
- insertData.insert(Thread.currentThread());
- };
- }.start();
- newThread(){
- publicvoid run(){
- insertData.insert(Thread.currentThread());
- };
- }.start();
- }
- }
- classInsertData{
- privateArrayList<Integer> arrayList =newArrayList<Integer>();
- publicvoid insert(Thread thread){
- for(int i=0;i<5;i++){
- System.out.println(thread.getName()+"在插入數據"+i);
- arrayList.add(i);
- }
- }
- }
這段代碼的執行是隨機的(每次結果都不一樣):
Thread-0在插入數據0 Thread-1在插入數據0 Thread-1在插入數據1 Thread-1在插入數據2 Thread-1在插入數據3 Thread-1在插入數據4 Thread-0在插入數據1 Thread-0在插入數據2 Thread-0在插入數據3 Thread-0在插入數據4
現在我們加上synchronized關鍵字來看看執行結果:
- publicsynchronizedvoid insert(Thread thread){
- for(int i=0;i<5;i++){
- System.out.println(thread.getName()+"在插入數據"+i);
- arrayList.add(i);
- }
- }
輸出:
Thread-0在插入數據0 Thread-0在插入數據1 Thread-0在插入數據2 Thread-0在插入數據3 Thread-0在插入數據4 Thread-1在插入數據0 Thread-1在插入數據1 Thread-1在插入數據2 Thread-1在插入數據3 Thread-1在插入數據4
可以發現,線程1會等待線程0插入完數據之後再執行,說明線程0和線程1是順序執行的。
從這兩個示例中,我們可以知道synchronized關鍵字可以實現方法同步互斥訪問。
在使用synchronized關鍵字的時候有幾個問題需要我們註意:
- 線上程調用synchronized的方法時,其他synchronized的方法是不能被訪問的,道理很簡單,一個對象只有一把鎖;
- 當一個線程在訪問對象的synchronized方法時,其他線程可以訪問該對象的非synchronized方法,因為訪問非synchronized不需要獲取鎖,是可以隨意訪問的;
- 如果一個線程A需要訪問對象object1的synchronized方法fun1,另外一個線程B需要訪問對象object2的synchronized方法fun1,即使object1和object2是同一類型),也不會產生線程安全問題,因為他們訪問的是不同的對象,所以不存在互斥問題。
synchronized代碼塊
synchronized代碼塊對於我們優化多線程的代碼很有幫助,首先我們來看看它長啥樣:
- synchronized(synObject){
- }
當在某個線程中執行該段代碼時,該線程會獲取到該對象的synObject鎖,此時其他線程無法訪問這段代碼塊,synchronized的值可以是this代表當前對象,也可以是對象的屬性,用對象的屬性時,表示的是對象屬性的鎖。
有了synchronized代碼塊,我們可以將上述添加數據的例子修改成如下兩種形式:
- classInsertData{
- privateArrayList<Integer> arrayList =newArrayList<Integer>();
- publicvoid insert(Thread thread){
- synchronized(this){
- for(int i=0;i<100;i++){
- System.out.println(thread.getName()+"在插入數據"+i);
- arrayList.add(i);
- }
- }
- }
- }
- classInsertData{
- privateArrayList<Integer> arrayList =newArrayList<Integer>();
- privateObjectobject=newObject();
- publicvoid insert(Thread thread){
- synchronized(object){
- for(int i=0;i<100;i++){
- System.out.println(thread.getName()+"在插入數據"+i);
- arrayList.add(i);
- }
- }
- }
- }
上述代碼就是synchronized代碼塊添加鎖的兩種方式,可以發現添加synchronized代碼塊,要比直接在方法上添加synchronized關鍵字更加靈活。
當我們用sychronized關鍵字修飾方法時,這個方法只能同時讓一個線程訪問,但是有時候很可能只有一部分代碼需要同步,而這個時候使用sychronized關鍵字修飾的方法是做不到的,但是使用sychronized代碼塊就可以實現這個功能。
並且如果一個線程執行一個對象的非static synchronized方法,另外一個線程需要執行這個對象所屬類的static synchronized方法,此時不會發生互斥現象,因為訪問static synchronized方法占用的是類鎖,而訪問非static synchronized方法占用的是對象鎖,所以不存在互斥現象。
來看一段代碼:
- publicclassTest{
- publicstaticvoid main(String[] args) {
- finalInsertData insertData =newInsertData();
- newThread(){
- publicvoid run(){
- insertData.insert();
- }
- }.start();
- newThread(){
- publicvoid run(){
- insertData.insert1();
- }
- }.start();
- }
- }
- classInsertData{
- publicsynchronizedvoid insert(){
- System.out.println("執行insert");
- try{
- Thread.sleep(5000);
- }catch(InterruptedException e){
- e.printStackT\frace();
- }
- System.out.println("執行insert完畢");
- }
- publicsynchronizedstaticvoid insert1(){
- System.out.println("執行insert1");
- System.out.println("執行insert1完畢");
- }
- }
執行結果:
執行insert 執行insert1 執行insert1完畢 執行insert完畢
編程要求
請仔細閱讀右側代碼,根據方法內的提示,在Begin - End區域內進行代碼補充,具體任務如下:
- 使num變數在同一時刻只能有一個線程可以訪問。
測試說明
使程式的輸出結果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
開始你的任務吧,祝你成功!
package step2; public class Task { public static void main(String[] args) { final insertData insert = new insertData(); for (int i = 0; i < 3; i++) { new Thread(new Runnable() { public void run() { insert.insert(Thread.currentThread()); } }).start(); } } } class insertData{ public static int num =0; /********* Begin *********/ public synchronized void insert(Thread thread){ for (int i = 0; i <= 5; i++) { num++; System.out.println(num); } } /********* End *********/ }
第1關:順序輸出
package step1; public class Task { public static void main(String[] args) throws Exception { /********* Begin *********/ //在這裡創建線程, 開啟線程 Object a = new Object(); //創建對象 a b c,用作線程間的同步鎖 Object b = new Object(); Object c = new Object(); MyThread th1 = new MyThread("AA",a,c); //創建MyThread 對象 th1 th2 th3,傳入線程名和兩個同步鎖對象 MyThread th2 = new MyThread("BB",c,b); MyThread th3 = new MyThread("CC",b,a); th1.start(); //調用 th1 的 start 方法,啟動線程 th1 Thread.sleep(10); //讓主線程睡眠 10 毫秒,保證 th1 先執行 th2.start(); //調用 th2 的 start 方法,啟動線程 th2 Thread.sleep(10); //讓主線程睡眠 10 毫秒,保證 th2 先執行 th3.start(); //調用 th3 的 start 方法,啟動線程 th3 Thread.sleep(10); //讓主線程睡眠 10 毫秒,保證 th3 先執行 System.exit(0); //退出程式 /********* End *********/ } } class MyThread extends Thread { /********* Begin *********/ String threadName; //定義一個字元串變數,用於存儲線程名 Object a = null; //定義一個對象變數,用於存儲同步鎖對象 a和b Object b = null; public MyThread(String threadName,Object a,Object b) { //定義一個構造方法,接收線程名和兩個同步鎖對象作為參數 super(); //調用父類的構造方法 this.threadName = threadName; //給 threadName 賦值 this.a=a; //分別給 a b 賦值 this.b=b; } public synchronized void run() { //重寫 run 方法,實現線程的邏輯 int count = 5; //定義一個整數變數 count,用於記錄列印次數 while(count > 0){ //當 count 大於 0 時迴圈執行以下代碼塊 synchronized (a){ //獲取 a 對象的鎖 synchronized (b){ //獲取 b 對象的鎖 System.out.println("Java Thread" + this.threadName); //輸出當前線程名 count--; //count -1 b.notify(); //喚醒等待 b 對象的鎖的其他線程(即下一個線程) } try { a.wait(); //釋放 a 對象的鎖,並讓當前線程等待(即進入阻塞狀態) }catch (InterruptedException e){ //捕獲可能拋出的異常 e.printStackTrace(); //列印異常信息 } } } } /********* End *********/ }
Java面向對象 - Java中的異常
Java 中的異常處理機制 (4.0分)
捕獲異常 (6.0分)
第1關:Java 中的異常處理機制
- 1、
在Java中,源文件Test.java中包含如下代碼段,則程式編譯運行結果是( )
- public class HelloWorld{
- public static void main(String[] args){
- System.out.print(“HelloWorld!”);
- }
- }
A、
輸出:HelloWorld!
B、
編譯出錯,提示“公有類HelloWorld必須在HelloWorld.java文件中定義”
C、
運行正常,但沒有輸出內容
D、
運行時出現異常
- 2、
關於下列代碼,說法正確的是()
- public static void main(String[] args){
- int num1 = 10;
- int num2 = 0;
- System.out.println(num1/num2);
- }
A、
輸出0
B、
編譯報錯,提示除數不能為0
C、
輸出無窮大
D、
運行時報錯,提示除數不能為0
第2關:捕獲異常
任務描述
本關任務:捕獲程式的異常,輸出異常處理的結果。
相關知識
為了完成本關任務,你需要掌握:1.如何捕獲異常。
捕獲異常
通過第一關我們知道,有一部分異常是需要程式員提前處理的,這種異常統一稱為檢測性異常,如果我們不處理,程式是不能編譯通過的,在IDE中也會出現一條紅線。
這個時候我們就必須處理這段可能出現異常的程式。
如何處理呢?
Java中提供了一個捕獲異常的機制:try-catch
通過這兩個單詞的字面意思我們就能很好的理解了:try:嘗試,catch:捕獲; 嘗試執行代碼A和代碼B如果這兩段代碼有一個出現了異常,就會執行catch中的語句,如果代碼A、B都不存在異常就不會執行catch代碼,最後繼續執行代碼C。
所以之前報錯的代碼我們這樣寫就沒錯啦:
在這裡我們可以發現catch捕獲的是FileNotFoundException,這是一個文件未找到異常,所以我們在捕獲異常的時候最好要先明確異常的種類是什麼。
好奇的同學可能會有疑惑,檢測性異常可以用try-catch來處理,那運行時異常可不可以用try-catch來處理呢?
可不可以呢?自己驗證一下吧!
編程要求
請仔細閱讀右側代碼,根據方法內的提示,在Begin - End區域內進行代碼補充,具體任務如下:
- 編輯器中的代碼運行時可能會有異常,請利用本關知識處理該異常。
測試說明
補充完代碼後,點擊測評,平臺會對你編寫的代碼進行測試,當你的結果與預期輸出一致時,即為通過。
輸入: 4 2
輸出: 2
輸入: 4 0
輸出: 除數不能為0
提示:捕獲異常需要用特定的類,下表總結了常用的異常類:
非檢測型異常:
異常 |
描述 |
ArithmeticException |
當出現異常的運算條件時,拋出此異常。例如,一個整數"除以零"時,拋出此類的一個實例。 |
ArrayIndexOutOfBoundsException |
用非法索引訪問數組時拋出的異常。如果索引為負或大於等於數組大小,則該索引為非法索引。 |
ClassCastException |
當試圖將對象強制轉換為不是實例的子類時,拋出該異常。 |
IllegalArgumentException |
拋出的異常表明向方法傳遞了一個不合法或不正確的參數。 |
IllegalMonitorStateException |
拋出的異常表明某一線程已經試圖等待對象的監視器,或者試圖通知其他正在等待對象的監視器而本身沒有指定監視器的線程。 |
IllegalStateException |
在非法或不適當的時間調用方法時產生的信號。換句話說,即 Java 環境或 Java 應用程式沒有處於請求操作所要求的適當狀態下。 |
IllegalThreadStateException |
線程沒有處於請求操作所要求的適當狀態時拋出的異常。 |
IndexOutOfBoundsException |
指示某排序索引(例如對數組、字元串或向量的排序)超出範圍時拋出。 |
NegativeArraySizeException |
如果應用程式試圖創建大小為負的數組,則拋出該異常。 |
NullPointerException |
當應用程式試圖在需要對象的地方使用 null 時,拋出該異常 |
NumberFormatException |
當應用程式試圖將字元串轉換成一種數值類型,但該字元串不能轉換為適當格式時,拋出該異常。 |
StringIndexOutOfBoundsException |
此異常由 String 方法拋出,指示索引或者為負,或者超出字元串的大小。 |
... |
... |
檢測性異常:
異常 |
描述 |
ClassNotFoundException |
應用程式試圖載入類時,找不到相應的類,拋出該異常。 |
CloneNotSupportedException |
當調用 Object 類中的 clone 方法克隆對象,但該對象的類無法實現 Cloneable 介面時,拋出該異常。 |
IllegalAccessException |
拒絕訪問一個類的時候,拋出該異常。 |
InstantiationException |
當試圖使用 Class 類中的 newInstance 方法創建一個類的實例,而指定的類對象因為是一個介面或是一個抽象類而無法實例化時,拋出該異常。 |
InterruptedException |
一個線程被另一個線程中斷,拋出該異常。 |
NoSuchFieldException |
請求的變數不存在 |
NoSuchMethodException |
請求的方法不存在 |
IOException及其子類 |
對文件或流的操作有誤時,拋出異常 |
... |
... |
開始你的任務吧,祝你成功!
package step2; import java.util.Scanner; public class Task { public static void main(String[] args) { Scanner sc = new Scanner(System.in); int num1 = sc.nextInt(); int num2 = sc.nextInt(); /********* Begin *********/ try{ System.out.println(num1/num2); } catch(Exception e){ System.out.println("除數不能為0"); } /********* End *********/ } }
Java高級特性 - IO流-2
字元流 - 輸入輸出 (10.0分)
第1關:字元流 - 輸入輸出
任務描述
本關任務:使用字元流對文本進行讀寫操作。
相關知識
為了完成本關任務,你需要掌握:
1.如何使用字元流讀數據;
2.如何使用字元流寫數據。
Writer
字元流的使用很簡單,和位元組輸入流類似,以FileWriter舉例:
執行上述代碼即可看到在D盤下創建了一個名為hello.txt的文件,文件的內容為hello。
上面代碼fw.flush()和fw.close()也可以省略fw.flush(),只寫fw.close()就可以了,但是都省略是不對的,如果都省略你會發現文本沒有寫入到hello.txt文件。
Reader
Reader的使用也很簡單,以FileReader為例:
輸出:
hello+ 1019個空格
使用上述代碼的會輸出hello.txt中的內容,但是會有一個問題:輸出hello的同時還輸出了1019個空格,這是什麼原因呢,如何解決這些問題呢?請你思考。
我們在下一關中揭曉答案。
編程要求
請仔細閱讀右側代碼,根據方法內的提示,在Begin - End區域內進行代碼補充,具體任務如下:
- 將src/step3/input/目錄下的txt文件複製到src/step3/output/目錄下;
- 複製的新文件命名為txt;
- txt文件中只有8個字元。
測試說明
補充完代碼後,點擊測評,平臺會對你編寫的代碼進行測試,當你的結果與預期輸出一致時,即為通過。
開始你的任務吧,祝你成功!
package step3; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; public class Task { public void task() throws IOException{ /********* Begin *********/ String file1 = "src/step3/input/input.txt"; //定義一個字元串變數,存儲輸入文件的路徑 FileReader fr = new FileReader(file1); //創建一個 FileReader 對象,用於讀取輸入文件的內容 char[] cbuf = new char[8]; //創建一個字元數組,用於存儲讀取到的字元 fr.read(cbuf); //調用 FileReader 的 read 方法,將輸入文件的前 8 個字元讀入到數組中 String file2 = "src/step3/output/output.txt"; //定義一個字元串變數,存儲輸出文件的路徑 FileWriter fw = new FileWriter(file2); //創建一個 FileWriter 對象,用於寫入輸出文件的內容 fw.write(cbuf); //調用 FileWriter 的 write 方法,將字元數組中的內容寫入到輸出文件中 fr.close(); //關閉 FileReader 對象,釋放資源 fw.flush(); //刷新 FileWriter 對象,將緩衝區中的內容寫入到文件中 fw.close(); //關閉 FileWriter 對象,釋放資源 /********* End *********/ } }
Java面向對象 - 類與對象-2
構造方法 (10.0分)
類與對象練習 (10.0分)
第1關:構造方法
package step2; import java.util.Scanner; public class Test { public static void main(String[] args) { Scanner sc = new Scanner(System.in); String name = sc.next(); String sex = sc.next(); /********** Begin **********/ //分別使用兩種構造器來創建Person對象 Person p1 = new Person(); Person p2 = new Person(name,sex); /********** End **********/ } } //創建Person對象,並創建兩種構造方法 /********** Begin **********/ class Person{ public Person(){ super(); System.out.println("一個人被創建了"); } public Person(String name,String sex){ super(); System.out.println("姓名:"+name+",性別:"+sex+",被創建了"); } } /********** End **********/
第2關:類與對象練習
package step4; //定義包名為step4 import java.util.Scanner; //導入Scanner類,用於接收用戶輸入 public class Test {