多態的概念:
- 多態性是指同一個操作作用于某一類對象,可以有不同的解釋,產生不同的執行結果。
- 多態存在的三個必要條件: ① 需要存在繼承或實現關系 ② 同樣的方法調用而執行不同的操作、運行不同代碼(重寫) ③ 在運行時父類或者接口的引用變量可以引用其子類的對象。
- 多態的作用: ① 多態通過分離做什么和怎么做,從一個角度將接口和實現進行分離。 ② 多態消除了類型之間的耦合關系 ③ 多態的存在提高了程序的拓展性和后期的可維護性。
abstract class Animal
{abstract void eat();
}
class dog extends Animal
{void eat(){System.out.println("狗啃骨頭");}
}
class cat extends Animal
{void eat(){System.out.println("貓吃魚");}
}
public class Main {public static void main(String[] args) {Animal an1=new dog();//在運行時父類或者接口的引用變量可以引用其子類的對象。向上轉型Animal an2=new cat();an1.eat();an2.eat();}
}
對象的上下轉型:
- 由子類轉換父類,在繼承圖上是向上移動的,一般稱為向上轉型
- 向上轉型是從一個較專用類型向通用類型轉換,所以總是安全的,也就是說,子類是父類的超集
- 向上轉型過程中,類接口中唯一可能發生的事情是丟失方法,而不是獲取方法
- 與之相反的操作是向下轉型,不安全(可能需要instanceof操作符協助)
- instanceof運算符用來在運行時通過返回值來指出對象是否有特定類或者它的子類的一個實例。典型使用場合:在對對象做下轉型之前,沒有其他有關對象信息時務必使用instanceof來判斷一下,以避免拋出ClassCastException異常。用法如下:
result=object instanceof class
result:布爾類型
object:必選項,任意對象表達式
class:必選項,任意已定義的對象類
說明:如果object是class或其子類的一個實例(引用),則instance運算符返回true如果不是或者object是null,則返回false
- 對象的上下轉型舉例:
abstract class Animal
{abstract void eat();
}
class dog extends Animal
{void eat(){System.out.println("狗啃骨頭");}void sleep(){System.out.println("狗狗睡覺");}
}
class cat extends Animal
{void eat(){System.out.println("貓吃魚");}
}
public class Main {public static void main(String[] args) {Animal an1=new dog();//在運行時父類或者接口的引用變量可以引用其子類的對象。Animal an2=new cat();an1.eat();//an1.sleep();向上轉型過程中,類接口中唯一可能發生的事情是丟失方法。這里就無法調用sleep方法//我感覺這里是因為父類沒有該方法,而子類有這個方法,所以這個方法會丟失。an2.eat();//cat cat1=(cat)an1;這樣強制向下轉型會拋出異常if(an1 instanceof cat){System.out.println("可以轉型");cat cat1=(cat)an1;//在這里并沒有輸出,因為an1并不是cat或其子類的一個實例(引用),}if(an2 instanceof cat){System.out.println("可以轉型");cat cat1=(cat)an2;//在這里有輸出,因為an2是cat的一個實例}}
}
- 不使用多態代碼示例:
class School
{CaiSeDaYinJi c1;HeiBaiDaYinJi h1;void AnzhuangDaYinJi(CaiSeDaYinJi c1){this.c1=c1;}void AnzhuangDaYinJi(HeiBaiDaYinJi h1){this.h1=h1;}void ShiYongCaiSeDaYinJi(String context){c1.print(context);}void ShiYongHeiBaiDaYinJi(String context){h1.print(context);}
}
abstract class DaYinJi
{String name;public DaYinJi(String name) {this.name=name;}abstract void print(String context);
}
class CaiSeDaYinJi extends DaYinJi
{public CaiSeDaYinJi(String name) {super(name);}void print(String context) {System.out.println(this.name+"彩色打印:"+context);}
}
class HeiBaiDaYinJi extends DaYinJi
{public HeiBaiDaYinJi(String name) {super(name);}void print(String context) {System.out.println(this.name+"黑白打印:"+context);}
}
public class Main {public static void main(String[] args) {CaiSeDaYinJi c1=new CaiSeDaYinJi("惠普1");HeiBaiDaYinJi h1=new HeiBaiDaYinJi("惠普2");School s=new School();s.AnzhuangDaYinJi(c1);s.AnzhuangDaYinJi(h1);s.ShiYongCaiSeDaYinJi("使用彩色打印打印");s.ShiYongHeiBaiDaYinJi("使用黑白打印打印"); }}
- 將上述代碼改為多態的形式進行編寫,方便代碼功能的添加使代碼耦合性更強。
class School
{DaYinJi d1;void AnzhuangDaYinJi(DaYinJi d1){this.d1=d1;}void ShiYongDaYinJi(String context){d1.print(context);}
}
abstract class DaYinJi
{String name;public DaYinJi(String name) {this.name=name;}abstract void print(String context);
}
class CaiSeDaYinJi extends DaYinJi
{public CaiSeDaYinJi(String name) {super(name);}void print(String context) {System.out.println(this.name+"彩色打印:"+context);}}
class HeiBaiDaYinJi extends DaYinJi
{public HeiBaiDaYinJi(String name) {super(name);}void print(String context) {System.out.println(this.name+"黑白打印:"+context);}
}
public class Main {public static void main(String[] args) {CaiSeDaYinJi c1=new CaiSeDaYinJi("惠普1");HeiBaiDaYinJi h1=new HeiBaiDaYinJi("惠普2");School s=new School();s.AnzhuangDaYinJi(c1);s.ShiYongDaYinJi("使用彩色打印");s.AnzhuangDaYinJi(h1);s.ShiYongDaYinJi("使用黑白打印");}
}
異常:
- 異常概念、異常分類、java異常處理機制、try…catch…finally、throw和throws、自定義異常
異常的概念:
- 什么是異常? 所謂的異常是指在程序運行的過程中發生的一些不正常事件(如:除0溢出,數組下標越界,所要讀取的文件不存在)。
- 異常導致的后果? java程序的執行過程中如出現異常事件,可以生成一個異常類對象,該異常對象封裝了異常事件的信息,并將其被提交給java運行時系統,這個過程稱為拋出異常,不處理的話會直接導致程序直接中斷。
- 如何防止程序中斷? 設計良好的程序應該在程序異常發生時提供處理這些異常的方法,使得程序不會因為異常的發生而阻斷或產生不可預見的結果。
- java異常的分類:分為error和Exception,error: 這個異常時系統運行java虛擬機的異常,和代碼沒有關系,這種異常我們一般處理不了,基本上都是要去檢查操作系統和檢查運行環境。Exception: 這個異常我們能夠處理,分為IOException和RuntimeException。
- 除了上面的異常分類之外我們還將異常分為以下類別:
異常類型 | 包括 | 來源 | 處理 |
---|---|---|---|
受檢查異常(checkException) | Exception及其子類(不包括RuntimeException) | 由代碼控制能力之外的因素導致的運行時錯誤 | 必須要處理,否則通不過編譯 |
非受查異常(uncheckedException) | Error和RuntimeException及其子類 | RuntimeException一般代表編程錯誤 | 可以不用處理 |
- 受檢查異常: 比如說:去讀取磁盤上某個文件,文件不存在或者要連接某個服務器而連不上,因為這些原因產生的異常就要處理,否則程序可能會運行到一半時崩了。
- 非受查異常: 比如說:java虛擬機運行時的異常或者程序代碼里面類似除數等于0這樣的異常或者多態處理上下轉型時的異常,這些都是編程時由于代碼問題而導致的編程錯誤,這種異常可以不用處理。
- java異常處理機制: Try-catch-finally, try: 監控區域,執行可能產生異常的代碼。catch: 捕獲、處理異常。finally: 善后處理,無論是否發生異常,代碼總能執行。
try{}
語句塊中放的代碼是要檢測的java代碼,可能會拋出異常,也可能會正常執行。catch(異常類型){}
塊是當java運行時系統接收到try塊中所拋出異常對象時,會尋找能處理這一異常catch塊來進行處理(可能有多個catch塊)。finally{}
不管系統有沒有拋出異常都會去執行,除了在之前執行了System.exit(0);
一般用來釋放資源。這幾部分代碼塊里面的代碼變量是不相關的,相當于局部變量吧。 - Java里try catch的簡單用法: ①try+catch: 程序的流程是:運行到try塊中,如果有異常拋出,則轉到catch塊去處理。然后執行catch塊后面的語句。②try+catch+finally: 程序的流程是:運行到try塊中,如果有異常拋出,則轉到catch塊,catch塊執行完畢后,執行finally塊的代碼,再執行finally塊后面的代碼。如果沒有異常拋出,執行完try塊,也要去執行finally塊的代碼。然后執行finally塊后面的語句。③try+finally: 程序的流程是:運行到try塊中,如果有異常拋出的話,程序轉向執行finally塊的代碼。那末finally塊后面的代碼還會被執行嗎?不會!因為沒有處理異常,所以遇到異常后,執行完finally后,方法就已拋出異常的方式退出了。
- 下面是java異常處理的示例代碼:
import java.util.Scanner;
class Person
{String name;
}
public class Main {public static void main(String[] args) {int a=10;int b;int c;Scanner sc=new Scanner(System.in);Person p=null;System.err.println("請輸入除數:");b=sc.nextInt();try{c=a/b;p.name="FHN";}catch(Exception e){ //Exception e這個是捕獲所有的異常,有了這句就不用寫下面的catch了System.out.println("空指針異常,請檢查有沒有初始化指針!");}
// catch(NullPointerException e){
// System.out.println("空指針異常,請檢查有沒有初始化指針!");
// }
// catch(ArithmeticException e){
// System.out.println("除數為0,請檢查輸入的除數,重新輸入!");
// b=sc.nextInt();
// c=a/b;
// System.out.println("c="+c);
// }finally{System.out.println("end");}System.out.println("end2");//如果在只用try和finally,在有異常時不會執行到這句,程序在這句之前就退出了}
}
throw和throws:
- throw用于手動拋出異常,作為程序員可以在任意位置手動拋出異常。
- throws用于在方法上標識要暴露的異常,拋出的異常交由調用者處理。
- 兩者區別: ① throw用在方法內,后面跟上要拋出的異常類對象。throws修飾在方法上,告訴調用者此方法可能會拋出異常,后面跟上可能要拋出異常類名。② throw:手動拋出異常。throws:聲明方法可能要拋出異常。
- 代碼示例:
class Bar
{int age;public Bar(int age) {this.age=age;}void check ()throws IllegalArgumentException //throws修飾在方法上,告訴調用者此方法可能會拋出異常,后面跟上可能要拋出異常類名。{if(age<18){throw new IllegalArgumentException("年紀太小");//年紀太小,會在異常拋出時顯示}}
}
public class Main {public static void main(String[] args) {Bar b=new Bar(15);try{b.check();}catch(IllegalArgumentException e){System.out.println(e.getMessage());e.printStackTrace();//顯示異常的數據}System.out.println("end");}
}
自定義異常:
- 常見異常:
RuntimeException、IOException、SQLException、ClassNotFoundException
- 自定義異常: java提供的異常體系不可能遇見所有加以報告的錯誤
- ① 自定義異常類必須從已由的異常類繼承。② 建立新的異常類型最簡單的方法就是讓編譯器產生默認構造方法。③ 對于異常來說,最重要的部分就是它的類名。 ④ 可以為異常類定義一個接受字符串參數的構造方法,字符串參數描述異常信息。
- 下面是使用自己定義的異常類,來手動拋出異常的代碼:
class Bar
{int age;public Bar(int age) {this.age=age;}void check ()throws AgeLess //throws修飾在方法上,告訴調用者此方法可能會拋出異常,后面跟上可能要拋出異常類名。{if(age<18){throw new AgeLess("年紀太小");//年紀太小,會在異常拋出時顯示}}
}
class AgeLess extends Exception //AgeLesss是自己定義的異常類,繼承自Exception,是首查異常
{private String message;public AgeLess(String message) {this.message=message;}public String getMessage() { //重寫了父類的getMessagereturn this.message;}
}
public class Main {public static void main(String[] args) {Bar b=new Bar(15);try{b.check();}catch(AgeLess e){System.out.println(e.getMessage());e.printStackTrace();//顯示異常的詳細數據,這里是父類的方法} System.out.println("end");}
}