一文搞懂Java異常

第8章 異常

本章學(xué)習(xí)目標(biāo)

  • 知道編譯時(shí)異常(受檢異常)與運(yùn)行時(shí)異常(非受檢異常)
  • 掌握常見(jiàn)的幾種異?;蝈e(cuò)誤類(lèi)型
  • 掌握try-catch結(jié)構(gòu)的語(yǔ)法格式和執(zhí)行特點(diǎn)
  • 掌握關(guān)鍵字finally的作用和特點(diǎn)
  • 掌握關(guān)鍵字throw的作用
  • 掌握關(guān)鍵字throws的作用
  • 知道throw與throws的區(qū)別
  • 了解Object類(lèi)clone方法的重寫(xiě)

8.1 異常概述

8.1.1 認(rèn)識(shí)Java的異常

  1. 什么是異常

    在使用計(jì)算機(jī)語(yǔ)言進(jìn)行項(xiàng)目開(kāi)發(fā)的過(guò)程中,即使程序員把代碼寫(xiě)得盡善盡美,在系統(tǒng)的運(yùn)行過(guò)程中仍然會(huì)遇到一些問(wèn)題,因?yàn)楹芏鄦?wèn)題不是靠代碼能夠避免的,比如:客戶(hù)輸入數(shù)據(jù)的格式問(wèn)題,讀取文件是否存在,網(wǎng)絡(luò)是否始終保持通暢等等。

    異常 :指的是程序在執(zhí)行過(guò)程中,出現(xiàn)的非正常的情況,如果不處理最終會(huì)導(dǎo)致JVM的非正常停止。

    異常指的并不是語(yǔ)法錯(cuò)誤,語(yǔ)法錯(cuò)了,編譯不通過(guò),不會(huì)產(chǎn)生字節(jié)碼文件,根本不能運(yùn)行.

    異常也不是指邏輯代碼錯(cuò)誤而沒(méi)有得到想要的結(jié)果,例如:求a與b的和,你寫(xiě)成了a-b

  2. 如何對(duì)待異常

    程序員在編寫(xiě)程序時(shí),就應(yīng)該充分考慮到各種可能發(fā)生的異常和錯(cuò)誤,極力預(yù)防和避免,實(shí)在無(wú)法避免的,要編寫(xiě)相應(yīng)的代碼進(jìn)行異常的檢測(cè)、異常消息的提示,以及異常的處理。

  3. 異常的拋出機(jī)制

    Java中是如何表示不同的異常情況,又是如何讓程序員得知,并處理異常的呢?

    Java中把不同的異常用不同的類(lèi)表示,一旦發(fā)生某種異常,就通過(guò)創(chuàng)建該異常類(lèi)型的對(duì)象,并且拋出,然后程序員可以catch到這個(gè)異常對(duì)象,并處理,如果無(wú)法catch到這個(gè)異常對(duì)象,那么這個(gè)異常對(duì)象將會(huì)導(dǎo)致程序終止。

    運(yùn)行下面的程序,程序會(huì)產(chǎn)生一個(gè)數(shù)組索引越界異常ArrayIndexOfBoundsException。我們通過(guò)圖解來(lái)解析下異常產(chǎn)生和拋出的過(guò)程。

    工具類(lèi)

    public class ArrayTools {
                // 對(duì)給定的數(shù)組通過(guò)給定的角標(biāo)獲取元素。
                public static int getElement(int[] arr, int index) {
                    int element = arr[index];
                    return element;
                }
            }

    測(cè)試類(lèi)

    public class ExceptionDemo {
                public static void main(String[] args) {
                    int[] arr = { 34, 12, 67 };
                    int num = ArrayTools.getElement(arr, 4);
                    System.out.println("num=" + num);
                    System.out.println("over");
                }
            }

    上述程序執(zhí)行過(guò)程圖解:

    1562772282750.png異常產(chǎn)生過(guò)程.png

8.1.2 Java異常體系

  1. Throwable

    `java.lang.Throwable` 類(lèi)是Java語(yǔ)言中所有錯(cuò)誤或異常的超類(lèi)。

    只有當(dāng)對(duì)象是此類(lèi)(或其子類(lèi)之一)的實(shí)例時(shí),才能通過(guò)Java 虛擬機(jī)或者Java的`throw` 語(yǔ)句拋出。類(lèi)似地,只有此類(lèi)或其子類(lèi)之一才可以是 `catch` 子句中的參數(shù)類(lèi)型。

  2. Error和Exception

    `Throwable`有兩個(gè)直接子類(lèi):`java.lang.Error`與`java.lang.Exception`,平常所說(shuō)的異常指`java.lang.Exception`。

    Error:表示嚴(yán)重錯(cuò)誤,一旦發(fā)生必須停下來(lái)查看問(wèn)題并解決問(wèn)題才能繼續(xù),無(wú)法僅僅通過(guò)try...catch解決的錯(cuò)誤。(如果拿生病做比喻,就像是突發(fā)疾病,而且是危重癥,必須立刻停下來(lái)治療而不是靠短暫休息、吃藥、打針、或小手術(shù)簡(jiǎn)單解決處理)

    例如:StackOverflowError(棧內(nèi)存溢出)和OutOfMemoryError(堆內(nèi)存溢出,簡(jiǎn)稱(chēng)OOM)。

    Exception:表示普通異常,其它因編程錯(cuò)誤或偶然的外在因素導(dǎo)致的一般性問(wèn)題,程序員可以通過(guò)代碼的方式檢測(cè)、提示和糾正,使程序繼續(xù)運(yùn)行,但是只要發(fā)生也是必須處理,否則程序也會(huì)掛掉。(這就好比普通感冒、闌尾炎、牙疼等,可以通過(guò)短暫休息、吃藥、打針、或小手術(shù)簡(jiǎn)單解決,但是也不能擱置不處理,不然也會(huì)要人命)。

    例如:空指針訪(fǎng)問(wèn)、試圖讀取不存在的文件、網(wǎng)絡(luò)連接中斷、數(shù)組下標(biāo)越界等

    無(wú)論是Error還是Exception,還有很多子類(lèi),異常的類(lèi)型非常豐富。當(dāng)代碼運(yùn)行出現(xiàn)異常時(shí),特別是我們不熟悉的異常時(shí),不要緊張,把異常的簡(jiǎn)單類(lèi)名,拷貝到API中去查去認(rèn)識(shí)它即可。

    簡(jiǎn)單的異常查看.bmp

8.1.3 受檢異常和非受檢異常

我們平常說(shuō)的異常就是指Exception,根據(jù)代碼的編寫(xiě)編譯階段,編譯器是否會(huì)警示當(dāng)前代碼可能發(fā)生xx異常,并督促程序員提前編寫(xiě)處理它的代碼為依據(jù),可以將異常分為:

  • 編譯時(shí)期異常(即checked異常、受檢異常):在代碼編譯階段,編譯器就能明確警示當(dāng)前代碼可能發(fā)生(不是一定發(fā)生)xx異常,并督促程序員提前編寫(xiě)處理它的代碼。如果程序員不聽(tīng)話(huà),沒(méi)有編寫(xiě)對(duì)應(yīng)的異常處理代碼,則編譯器就會(huì)發(fā)威,直接判定編譯失敗,從而程序無(wú)法執(zhí)行。通常,這類(lèi)異常的發(fā)生不是由程序員的代碼引起的,或者不是靠加簡(jiǎn)單判斷就可以避免的,例如:FileNotFoundException(文件找不到異常)。
  • 運(yùn)行時(shí)期異常(即runtime異常、unchecked非受檢異常):即在代碼編譯階段,編譯器完全不做任何檢查,無(wú)論該異常是否會(huì)發(fā)生,編譯器都不給出任何提示。只有等代碼運(yùn)行起來(lái)并確實(shí)發(fā)生了xx異常,它才能被發(fā)現(xiàn)。通常,這類(lèi)異常是由程序員的代碼編寫(xiě)不當(dāng)引起的,只要稍加判斷,或者細(xì)心檢查就可以避免的。例如:ArrayIndexOutOfBoundsException數(shù)組下標(biāo)越界異常,ClassCastException類(lèi)型轉(zhuǎn)換異常。
1562771528807.png

8.1.4 演示常見(jiàn)的錯(cuò)誤和異常

  1. Error

    最常見(jiàn)的就是VirtualMachineError,它有兩個(gè)經(jīng)典的子類(lèi):StackOverflowError、OutOfMemoryError。

    package com.atguigu.exception;
    
            import org.junit.Test;
    
            public class TestStackOverflowError {
                @Test
                public void test01() {
                    //StackOverflowError
                    digui();
                }
    
                public void digui() {
                    digui();
                }
            }
    package com.atguigu.exception;
    
            import org.junit.Test;
    
            public class TestOutOfMemoryError {
                @Test
                public void test02() {
                    //OutOfMemoryError
                    //方式一:
                    int[] arr = new int[Integer.MAX_VALUE];
                }
                @Test
                public void test03() {
                    //OutOfMemoryError
                    //方式二:
                    StringBuilder s = new StringBuilder();
                    while (true) {
                        s.append("atguigu");
                    }
                }
            }
  2. 非受檢的運(yùn)行時(shí)異常

    package com.atguigu.exception;
    
            import org.junit.Test;
    
            import java.util.Scanner;
    
            public class TestRuntimeException {
                @Test
                public void test01() {
                    //NullPointerException
                    int[][] arr = new int[3][];
                    System.out.println(arr[0].length);
                }
    
                @Test
                public void test02() {
                    //ClassCastException
                    Object obj = 15;
                    String str = (String) obj;
                }
    
                @Test
                public void test03() {
                    //ArrayIndexOutOfBoundsException
                    int[] arr = new int[5];
                    for (int i = 1; i <= 5; i++) {
                        System.out.println(arr[i]);
                    }
                }
    
                @Test
                public void test04() {
                    //InputMismatchException
                    Scanner input = new Scanner(System.in);
                    System.out.print("請(qǐng)輸入一個(gè)整數(shù):");//輸入非整數(shù)
                    int num = input.nextInt();
                    input.close();
                }
    
                @Test
                public void test05() {
                    int a = 1;
                    int b = 0;
                    //ArithmeticException
                    System.out.println(a / b);
                }
            }
  3. 受檢的編譯時(shí)異常

    package com.atguigu.exception;
    
            import org.junit.Test;
    
            import java.io.FileInputStream;
    
            public class TestCheckedException {
                @Test
                public void test06() {
                    Thread.sleep(1000);//休眠1秒,編譯報(bào)錯(cuò)
                }
    
                @Test
                public void test07()  {
                    FileInputStream fis = new FileInputStream("Java學(xué)習(xí)秘籍.txt");//編譯報(bào)錯(cuò)
                }
    
            }

8.2 異常的處理

Java異常處理的五個(gè)關(guān)鍵字:try、catch、finally、throw、throws

8.2.1 捕獲異常:try…catch

當(dāng)某段代碼可能發(fā)生異常,不管這個(gè)異常是編譯時(shí)異常(受檢異常)還是運(yùn)行時(shí)異常(非受檢異常),我們都可以使用try塊將它括起來(lái),并在try塊下面編寫(xiě)catch分支嘗試捕獲對(duì)應(yīng)的異常對(duì)象。

try...catch語(yǔ)法格式:

try{
     可能發(fā)生xx異常的代碼
}catch(異常類(lèi)型1  e){
     處理異常的代碼1
}catch(異常類(lèi)型2  e){
     處理異常的代碼2
}
....
try{
     可能發(fā)生xx異常的代碼
}catch(異常類(lèi)型1 | 異常類(lèi)型2  e){
     處理異常的代碼1
}catch(異常類(lèi)型3  e){
     處理異常的代碼2
}
....
  1. try{}中編寫(xiě)可能發(fā)生xx異常的業(yè)務(wù)邏輯代碼。
  2. catch分支,分為兩個(gè)部分,catch()中編寫(xiě)異常類(lèi)型和異常參數(shù)名,{}中編寫(xiě)如果發(fā)生了這個(gè)異常,要做什么處理的代碼。如果有多個(gè)catch分支,并且多個(gè)異常類(lèi)型有父子類(lèi)關(guān)系,必須保證小的子異常類(lèi)型在上,大的父異常類(lèi)型在下。
  3. 在catch分支中如何獲取異常信息,Throwable類(lèi)中定義了一些查看方法:
  • `public String getMessage()`:獲取異常的描述信息,原因(提示給用戶(hù)的時(shí)候,就提示錯(cuò)誤原因。
  • `public void printStackTrace()`:打印異常的跟蹤棧信息并輸出到控制臺(tái)。

包含了異常的類(lèi)型,異常的原因,還包括異常出現(xiàn)的位置,在開(kāi)發(fā)和調(diào)試階段,都得使用printStackTrace。

  1. 執(zhí)行流程
  • 如果在程序運(yùn)行時(shí),try塊中的代碼沒(méi)有發(fā)生異常,那么catch所有的分支都不執(zhí)行。
  • 如果在程序運(yùn)行時(shí),try塊中的代碼發(fā)生了異常,根據(jù)異常對(duì)象的類(lèi)型,將從上到下選擇第一個(gè)匹配的catch分支執(zhí)行。此時(shí)try中發(fā)生異常的語(yǔ)句下面的代碼將不執(zhí)行,而整個(gè)try...catch之后的代碼可以繼續(xù)運(yùn)行。
  • 如果在程序運(yùn)行時(shí),try塊中的代碼發(fā)生了異常,但是所有catch分支都無(wú)法匹配(捕獲)這個(gè)異常,那么JVM將會(huì)終止當(dāng)前方法的執(zhí)行,并把異常對(duì)象“拋”給調(diào)用者。如果調(diào)用者不處理,程序就掛了。

示例代碼:

package com.atguigu.test;

import java.util.Scanner;

public class TestTryCatch1 {
    public static void main(String[] args) {

        Scanner input = new Scanner(System.in);

        int m;
        while (true) {
            try {
                System.out.print("請(qǐng)輸入一個(gè)正整數(shù):");
                m = input.nextInt();

                if (m < 0) {
                    System.out.println("輸入有誤," + m + "不是正整數(shù)!");
                } else {
                    break;
                }
            } catch (InputMismatchException e) {
                //String result = input.nextLine();
                //System.out.println("輸入有誤," + result + "不是整數(shù)");
                e.printStackTrace();
            }
        }

        System.out.println("m = " + m);
    }
}

8.2.2 finally塊

  1. finally塊

    因?yàn)楫惓?huì)引發(fā)程序跳轉(zhuǎn),從而會(huì)導(dǎo)致有些語(yǔ)句執(zhí)行不到。而程序中有一些特定的代碼無(wú)論異常是否發(fā)生,都需要執(zhí)行。例如,IO流的關(guān)閉,數(shù)據(jù)庫(kù)連接的斷開(kāi)等。這樣的代碼通常就會(huì)放到finally塊中。

     try{
                 
             }catch(...){
                 
             }finally{
                 無(wú)論try中是否發(fā)生異常,也無(wú)論catch是否捕獲異常,也不管try和catch中是否有return語(yǔ)句,都一定會(huì)執(zhí)行
             }
             
              或
               try{
                 
             }finally{
                 無(wú)論try中是否發(fā)生異常,也不管try中是否有return語(yǔ)句,都一定會(huì)執(zhí)行。
             } 

    注意:finally不能單獨(dú)使用。

    當(dāng)只有在try或者catch中調(diào)用退出JVM的相關(guān)方法,例如System.exit(0),此時(shí)finally才不會(huì)執(zhí)行,否則finally永遠(yuǎn)會(huì)執(zhí)行。

    示例代碼:

    package com.atguigu.keyword;
    
            import java.util.InputMismatchException;
            import java.util.Scanner;
    
            public class TestFinally {
                public static void main(String[] args) {
                    Scanner input = new Scanner(System.in);
                    try {
                        System.out.print("請(qǐng)輸入第一個(gè)整數(shù):");
                        int a = input.nextInt();
                        System.out.print("請(qǐng)輸入第二個(gè)整數(shù):");
                        int b = input.nextInt();
                        int result = a / b;
                        System.out.println(a + "/" + b + "=" + result);
                    } catch (InputMismatchException e) {
                        System.out.println("數(shù)字格式不正確,請(qǐng)輸入兩個(gè)整數(shù)");
                    } catch (ArithmeticException e) {
                        System.out.println("第二個(gè)整數(shù)不能為0");
                    } finally {
                        System.out.println("程序結(jié)束,釋放資源");
                        input.close();
                    }
                }
            }

  2. finally與return

    finally中寫(xiě)了return語(yǔ)句,那么try和catch中的return語(yǔ)句就失效了,最終返回的是finally塊中的

    形式一:從try回來(lái)

    public class TestReturn {
                public static void main(String[] args) {
                    int result = test("12");
                    System.out.println(result);
                }
    
                public static int test(String str) {
                    try {
                        Integer.parseInt(str);
                        return 1;
                    } catch (NumberFormatException e) {
                        return -1;
                    } finally {
                        System.out.println("test結(jié)束");
                    }
                }
            }

    形式二:從catch回來(lái)

    public class TestReturn {
                public static void main(String[] args) {
                    int result = test("a");
                    System.out.println(result);
                }
    
                public static int test(String str) {
                    try {
                        Integer.parseInt(str);
                        return 1;
                    } catch (NumberFormatException e) {
                        return -1;
                    } finally {
                        System.out.println("test結(jié)束");
                    }
                }
            }

    形式三:從finally回來(lái)

    public class TestReturn {
                public static void main(String[] args) {
                    int result = test("a");
                    System.out.println(result);
                }
    
                public static int test(String str) {
                    try {
                        Integer.parseInt(str);
                        return 1;
                    } catch (NumberFormatException e) {
                        return -1;
                    } finally {
                        System.out.println("test結(jié)束");
                        return 0;
                    }
                }
            }

8.2.3 手工拋出異常對(duì)象:throw

  1. 異常對(duì)象生成的兩種方式
    • 由虛擬機(jī)自動(dòng)生成:程序運(yùn)行過(guò)程中,虛擬機(jī)檢測(cè)到程序發(fā)生了問(wèn)題,就會(huì)在后臺(tái)自動(dòng)創(chuàng)建一個(gè)對(duì)應(yīng)異常類(lèi)的實(shí)例對(duì)象并拋出——自動(dòng)拋出。適用于核心類(lèi)庫(kù)中預(yù)定義的異常類(lèi)型。
    • 由開(kāi)發(fā)人員手動(dòng)創(chuàng)建:new 異常類(lèi)型(【實(shí)參列表】);,如果創(chuàng)建好的異常對(duì)象不拋出對(duì)程序沒(méi)有任何影響,和創(chuàng)建一個(gè)普通對(duì)象一樣,但是一旦throw拋出,就會(huì)對(duì)程序運(yùn)行產(chǎn)生影響了。適用于預(yù)定義類(lèi)型和自定義異常。
  2. throw異常對(duì)象的語(yǔ)法格式

    throw new 異常類(lèi)名(【參數(shù)】);

    throw語(yǔ)句拋出的異常對(duì)象,和JVM自動(dòng)創(chuàng)建和拋出的異常對(duì)象一樣,需要處理。如果沒(méi)有被try..catch合理的處理,也會(huì)導(dǎo)致程序崩潰。

    throw語(yǔ)句會(huì)導(dǎo)致程序執(zhí)行流程被改變,throw語(yǔ)句是明確拋出一個(gè)異常對(duì)象,因此它下面的代碼將不會(huì)執(zhí)行,如果當(dāng)前方法沒(méi)有try...catch處理這個(gè)異常對(duì)象,throw語(yǔ)句就會(huì)代替return語(yǔ)句提前終止當(dāng)前方法的執(zhí)行,并返回一個(gè)異常對(duì)象給調(diào)用者。

    package com.atguigu.throwdemo;
    
            public class TestThrow {
                public static void main(String[] args) {
                    try {
                        System.out.println(max(4, 2, 31, 1));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    try {
                        System.out.println(max(4));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    try {
                        System.out.println(max());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
    
                public static int max(int... nums) {
                    if (nums == null || nums.length == 0) {
                        throw new IllegalArgumentException("沒(méi)有傳入任何整數(shù),無(wú)法獲取最大值");
                    }
                    int max = nums[0];
                    for (int i = 1; i < nums.length; i++) {
                        if (nums[i] > max) {
                            max = nums[i];
                        }
                    }
                    return max;
                }
            }

8.2.4 聲明方法可能拋出的異常:throws

  1. throws編譯時(shí)異常

    如果在編寫(xiě)方法體的代碼時(shí),某句代碼可能發(fā)生某個(gè)編譯時(shí)異常,不處理編譯不通過(guò),但是在當(dāng)前方法體中可能不適合處理或無(wú)法給出合理的處理方式,就可以通過(guò)throws在方法簽名中聲明該方法可能會(huì)發(fā)生xx異常,需要調(diào)用者處理。

    聲明異常格式:

    修飾符 返回值類(lèi)型 方法名(參數(shù)) throws 異常類(lèi)名1,異常類(lèi)名2…{   }

    在throws后面可以寫(xiě)多個(gè)異常類(lèi)型,用逗號(hào)隔開(kāi)。

    package com.atguigu.test;
    
            public class Triangle {
                private final double a;
                private final double b;
                private final double c;
    
                public Triangle(double a, double b, double c) throws Exception {
                    if (a <= 0 || b <= 0 || c <= 0) {
                        throw new Exception("三角形的邊長(zhǎng)必須是正數(shù),不能為負(fù)數(shù)");
                    }
                    if (a + b <= c || b + c <= a || a + c <= b) {
                        throw new Exception(a + "," + b + "," + c + "不能構(gòu)造三角形,三角形任意兩邊之后必須大于第三邊");
                    }
                    this.a = a;
                    this.b = b;
                    this.c = c;
                }
    
                public double getA() {
                    return a;
                }
    
                public double getB() {
                    return b;
                }
    
                public double getC() {
                    return c;
                }
    
                @Override
                public String toString() {
                    return "Triangle{" +
                            "a=" + a +
                            ", b=" + b +
                            ", c=" + c +
                            '}';
                }
            }
    package com.atguigu.test;
    
            public class TestThrows {
                public static void main(String[] args)  {
                    try {
                        Triangle t1 = new Triangle(2, 2, 3);
                        System.out.println("三角形1創(chuàng)建成功:" + t1);
                    } catch (Exception  e) {
                        System.err.println("三角形1創(chuàng)建失敗");
                        e.printStackTrace();
                    } 
                    try {
                        Triangle t2 = new Triangle(1, 1, 3);
                        System.out.println("三角形2創(chuàng)建成功:" + t2);
                    } catch (Exception e) {
                        System.err.println("三角形2創(chuàng)建失敗");
                        e.printStackTrace();
                    } 
                }
            }
  2. throws運(yùn)行時(shí)異常

    當(dāng)然,throws后面也可以寫(xiě)運(yùn)行時(shí)異常類(lèi)型,只是運(yùn)行時(shí)異常類(lèi)型,寫(xiě)或不寫(xiě)對(duì)于編譯器和程序執(zhí)行來(lái)說(shuō)都沒(méi)有任何區(qū)別。如果寫(xiě)了,唯一的區(qū)別就是調(diào)用者調(diào)用該方法后,使用try...catch結(jié)構(gòu)時(shí),IDEA可以獲得更多的信息,需要添加什么catch分支。

    package com.atguigu.test;
    
            public class TestThrowsRuntimeException {
                public static void main(String[] args) {
                    try {
                        System.out.println(divide(1, 2));
                    } catch (ArithmeticException e) {
                        throw new RuntimeException(e);
                    }
                }
    
                public static int divide(int a, int b) throws ArithmeticException {
                    return a / b;
                }
            }

8.3 方法重寫(xiě)對(duì)于throws要求

  1. 方法重寫(xiě)對(duì)于throws要求

    方法重寫(xiě)時(shí),對(duì)于方法簽名是有嚴(yán)格要求的:

    1. 方法名必須相同
    2. 形參列表必須相同
    3. 返回值類(lèi)型
    • 基本數(shù)據(jù)類(lèi)型和void:必須相同
    • 引用數(shù)據(jù)類(lèi)型:<=
    1. 權(quán)限修飾符:>=,而且要求父類(lèi)被重寫(xiě)方法在子類(lèi)中是可見(jiàn)的
    2. 不能是static,final修飾的方法
    3. throws異常列表要求
    • 如果父類(lèi)被重寫(xiě)方法的方法簽名后面沒(méi)有 “throws 編譯時(shí)異常類(lèi)型”,那么重寫(xiě)方法時(shí),方法簽名后面也不能出現(xiàn)“throws 編譯時(shí)異常類(lèi)型”。
    • 如果父類(lèi)被重寫(xiě)方法的方法簽名后面有 “throws 編譯時(shí)異常類(lèi)型”,那么重寫(xiě)方法時(shí),throws的編譯時(shí)異常類(lèi)型必須<=被重寫(xiě)方法throws的編譯時(shí)異常類(lèi)型,或者不throws編譯時(shí)異常。
    • 方法重寫(xiě),對(duì)于“throws 運(yùn)行時(shí)異常類(lèi)型”沒(méi)有要求。
    package com.atguigu.keyword;
    
            import java.io.IOException;
    
            public class TestOverride {
    
            }
    
            class Father {
                public void method() throws Exception {
                    System.out.println("Father.method");
                }
            }
            class Son extends Father {
                @Override
                public void method() throws IOException, ClassCastException {
                    System.out.println("Son.method");
                }
            }
  2. Object的clone方法和java.lang.Cloneable接口

    在java.lang.Object類(lèi)中有一個(gè)方法:

    protected Object clone() throws CloneNotSupportedException 

    所有類(lèi)型都可以重寫(xiě)這個(gè)方法,它是獲取一個(gè)對(duì)象的克隆體對(duì)象用的,就是造一個(gè)和當(dāng)前對(duì)象各種屬性值一模一樣的對(duì)象。當(dāng)然地址肯定不同。

    我們?cè)谥貙?xiě)這個(gè)方法后時(shí),調(diào)用super.clone(),發(fā)現(xiàn)報(bào)異常CloneNotSupportedException,因?yàn)槲覀儧](méi)有實(shí)現(xiàn)java.lang.Cloneable接口。

    class Teacher implements Cloneable {
                private int id;
                private String name;
                public Teacher(int id, String name) {
                    super();
                    this.id = id;
                    this.name = name;
                }
                public Teacher() {
                    super();
                }
                public int getId() {
                    return id;
                }
                public void setId(int id) {
                    this.id = id;
                }
                public String getName() {
                    return name;
                }
                public void setName(String name) {
                    this.name = name;
                }
                @Override
                public String toString() {
                    return "Teacher [id=" + id + ", name=" + name + "]";
                }
                @Override
                public Teacher clone() throws CloneNotSupportedException {
                    return (Teacher) super.clone();
                }
    
            }
    public class TestClonable {
                public static void main(String[] args) throws CloneNotSupportedException {
                    Teacher src = new Teacher(1, "柴老師");
                    Teacher clone = src.clone();
                    System.out.println(clone);
                    System.out.println(src);
                    System.out.println(src == clone);
                }
            }