多態(tài):一個(gè)對(duì)象具備多種形態(tài)旷偿。(父類的引用類型變量指向了子類的對(duì)象)
或者是接口 的引用類型變量指向了接口實(shí)現(xiàn)類的對(duì)象)
運(yùn)行時(shí)多態(tài)存在的三個(gè)必要條件:
- 要有繼承(包括接口的實(shí)現(xiàn))值依;
- 要有重寫鳄乏;
- 父類引用指向子類對(duì)象籍茧。
父類 a = new 子類();
運(yùn)行時(shí)多態(tài)的解釋:
1.運(yùn)行時(shí)多態(tài)是指程序中定義的引用變量所指向的具體類型
2.通過該引用變量發(fā)出的方法調(diào)用在編程時(shí)并不確定闷板,而是在程序運(yùn)行期間才確定架谎,即一個(gè)引用變量倒底會(huì)指向哪個(gè)類的實(shí)例對(duì)象讲冠,該引用變量發(fā)出的方法調(diào)用到底是哪個(gè)類中實(shí)現(xiàn)的方法先鱼,必須在由程序運(yùn)行期間才能決定.
多態(tài)的好處:
1.可替換性(substitutability)俭正。多態(tài)對(duì)已存在代碼具有可替換性。例如焙畔,多態(tài)對(duì)圓Circle類工作掸读,對(duì)其他任何圓形幾何體,如圓環(huán)宏多,也同樣工作儿惫。
2.可擴(kuò)充性(extensibility)。多態(tài)對(duì)代碼具有可擴(kuò)充性伸但。增加新的子類不影響已存在類的多態(tài)性肾请、繼承性,以及其他特性的運(yùn)行和操作更胖。實(shí)際上新加子類更容易獲得多態(tài)功能铛铁。例如,在實(shí)現(xiàn)了圓錐却妨、半圓錐以及半球體的多態(tài)基礎(chǔ)上饵逐,很容易增添球體類的多態(tài)性。
3.接口性(interface-ability)管呵。多態(tài)是超類通過方法簽名梳毙,向子類提供了一個(gè)共同接口,由子類來完善或者覆蓋它而實(shí)現(xiàn)的捐下。超類Shape規(guī)定了兩個(gè)實(shí)現(xiàn)多態(tài)的接口方法账锹,computeArea()以及computeVolume()。子類坷襟,如Circle和Sphere為了實(shí)現(xiàn)多態(tài)奸柬,完善或者覆蓋這兩個(gè)接口方法。
4.靈活性(flexibility)婴程。它在應(yīng)用中體現(xiàn)了靈活多樣的操作廓奕,提高了使用效率。
5.簡(jiǎn)化性(simplicity)。多態(tài)簡(jiǎn)化對(duì)應(yīng)用軟件的代碼編寫和修改過程桌粉,尤其在處理大量對(duì)象的運(yùn)算和操作時(shí)蒸绩,這個(gè)特點(diǎn)尤為突出和重要。
多態(tài)的應(yīng)用:
- 多態(tài)用于形參類型的時(shí)候铃肯,可以接收更多類型的數(shù)據(jù) 患亿。
- 多態(tài)用于返回值類型的時(shí)候,可以返回更多類型的數(shù)據(jù)押逼。
多態(tài)要注意 的細(xì)節(jié):
1. 多態(tài)情況下步藕,子父類存在同名的成員變量時(shí),訪問的是父類的成員變量挑格。
2. 多態(tài)情況下咙冗,子父類存在同名的非靜態(tài)的成員函數(shù)時(shí),訪問的是子類的成員函數(shù)漂彤。
3. 多態(tài)情況下雾消,子父類存在同名的靜態(tài)的成員函數(shù)時(shí),訪問的是父類的成員函數(shù)显歧。
4. 多態(tài)情況下仪或,不能訪問子類特有的成員。
總結(jié):多態(tài)情況下士骤,子父類存在同名的成員時(shí)范删,訪問的都是父類的成員,除了在同名非靜態(tài)函數(shù)時(shí)才是訪問子類的拷肌。
編譯看左邊到旦,運(yùn)行不一定看右邊。
編譯看左邊:java編譯器在編譯的時(shí)候巨缘,會(huì)檢查引用類型變量所屬的類是否具備指定的成員添忘,如果不具備馬上編譯報(bào)錯(cuò)
- 成員內(nèi)部類
第一種:內(nèi)部類:
一個(gè)類定義在另外一個(gè)類的內(nèi)部,那么該類就稱作為內(nèi)部類若锁。
內(nèi)部類的class文件名: 外部類$內(nèi)部類. 好處:便于區(qū)分該class文件是屬于哪個(gè)外部類的搁骑。
內(nèi)部類的類別:
成員內(nèi)部類:
成員內(nèi)部類的訪問方式:
1.在外部類提供一個(gè)方法創(chuàng)建內(nèi)部類的對(duì)象進(jìn)行訪問。
2.在其他類直接創(chuàng)建內(nèi)部類的對(duì)象又固。 格式:
外部類.內(nèi)部類 變量名 = new 外部類().new 內(nèi)部類();
注意: 如果是一個(gè)靜態(tài)內(nèi)部類仲器,那么在其他類創(chuàng)建 的格式:
外部類.內(nèi)部類 變量名 = new 外部類.內(nèi)部類();
內(nèi)部類的應(yīng)用場(chǎng)景: 我們?cè)诿枋鯝事物的時(shí)候,發(fā)現(xiàn)描述的A事物內(nèi)部還存在另外一個(gè)比較復(fù)雜的事物B時(shí)候仰冠,而且這個(gè)比較復(fù)雜事物B還需要訪問A事物的屬性等數(shù)據(jù)乏冀,那么這時(shí)候我們就可以使用內(nèi)部類描述B事物。
內(nèi)部類的好處:內(nèi)部類可以直接訪問外部類的所有成員洋只。
內(nèi)部類要注意的細(xì)節(jié):
- 如果外部類與內(nèi)部類存在同名的成員變量時(shí)辆沦,在內(nèi)部類中默認(rèn)情況下是訪問內(nèi)部類的成員變量昼捍。
可以通過"外部類.this.成員變量名" 指定訪問外部類的 成員。 - 私有的成員內(nèi)部類只能在外部類提供一個(gè)方法創(chuàng)建內(nèi)部類的對(duì)象進(jìn)行訪問肢扯,不能在其他類創(chuàng)建對(duì)象了妒茬。
- 成員內(nèi)部類一旦出現(xiàn)了靜態(tài)的成員,那么該類也必須 使用static修飾蔚晨。
第二種:局部?jī)?nèi)部類
局部?jī)?nèi)部類: 在一個(gè)類 的方法內(nèi)部定義另外一個(gè)類郊闯,那么另外一個(gè)類就稱作為局部?jī)?nèi)部類。
局部?jī)?nèi)部類要注意的細(xì)節(jié):
如果局部 內(nèi)部類訪問了一個(gè)局部變量蛛株,那么該局部變量必須使用final修飾、
第三種:匿名內(nèi)部類
:沒有類名的類就稱作為匿名內(nèi)部類育拨。
匿名內(nèi)部類的好處:簡(jiǎn)化書寫谨履。
匿名內(nèi)部類的使用前提:必須存在繼承或者實(shí)現(xiàn)關(guān)系才能使用。
public class UserAccount {
public void print() {
/// 需求: 在方法內(nèi)部定義一個(gè)類繼承自Person類熬丧,然后執(zhí)行eat和sleep方法笋粟,
/**
* 第一種方式:局部?jī)?nèi)部類的方式,此種方式比較麻煩
class Student extends Person {
public Student(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println(name +"吃飯");
}
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println(name +"睡覺");
}
}
/// 創(chuàng)建對(duì)象調(diào)用run和sleep方法
Student student = new Student("楊孝遠(yuǎn)");
student.eat();
student.sleep();
*/
/*
* 第二種方式: 匿名內(nèi)部類
*/
Person person = new Person("楊孝遠(yuǎn)") {
@Override
public void sleep() {
// TODO Auto-generated method stub
System.out.println(name +"睡覺覺");
}
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println(name +"池吃吃吃");
}
};
person.sleep();
person.eat();
}
}
/// 這樣調(diào)用
public static void main(String[] args) {
UserAccount userAccount = new UserAccount();
userAccount.print();
}
匿名內(nèi)部類一般是用于實(shí)參析蝴, 比如以下代碼
public static void main(String[] args) {
test(new Dao() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("跑跑跑跑跑");
}
});
}
public static void test(Dao dao) {
dao.run();
}
實(shí)現(xiàn)關(guān)系下匿名內(nèi)部類
/// 實(shí)現(xiàn)關(guān)系下的匿名函數(shù)
// 警告: the type is already defined 原因:接口名與其他接口名存在沖突相同害捕,修改下接口名即可
interface Dao {
public abstract void run();
}
public class User {
public void print() {
/// 匿名函數(shù)
new Dao() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("跑啊跑");
}
}.run();;
}
}
疑問: 什么時(shí)候使用內(nèi)部類呢?
當(dāng)我們分析事物時(shí)闷畸,發(fā)現(xiàn)事物的內(nèi)部還有具體的事物尝盼,這時(shí)則應(yīng)該定義內(nèi)部類了。
比如人體是一個(gè)類佑菩,人體有心臟盾沫,心臟的功能在直接訪問人體的其他內(nèi)容。這時(shí)就將心臟定義在人體類中殿漠,作為內(nèi)部類存在赴精。
內(nèi)部類的優(yōu)勢(shì):成員內(nèi)部類作為外部類的成員,那么可以訪問外部類的任意成員绞幌。
- java 異常處理 Throwable Error 和Exception
在Java中蕾哟,根據(jù)錯(cuò)誤性質(zhì)將運(yùn)行錯(cuò)誤分為兩類:錯(cuò)誤和異常。
在Java程序的執(zhí)行過程中莲蜘,如果出現(xiàn)了異常事件谭确,就會(huì)生成一個(gè)異常對(duì)象。生成的異常對(duì)象將傳遞Java運(yùn)行時(shí)系統(tǒng)菇夸,這一異常的產(chǎn)生和提交過程稱為拋棄(throw)異常琼富。
當(dāng)Java運(yùn)行時(shí)系統(tǒng)得到一個(gè)異常對(duì)象時(shí),它將會(huì)沿著方法的調(diào)用棧逐層回溯庄新,尋找處理這一異常的代碼鞠眉。找到能夠處理這類異常的方法后薯鼠,運(yùn)行時(shí)系統(tǒng)把當(dāng)前異常對(duì)象交給這個(gè)方法進(jìn)行處理,這一過程稱為捕獲(catch)異常械蹋。
Java中的所有異常都是由Throwable類的子類生成的對(duì)象出皇,所有的異常類都是Throwable類的子類或子類的子類。Throwable類是Object類的直接子類哗戈,Error類和Exception類是Throwable類的兩個(gè)直接子類郊艘。
Throwable常用的方法:
toString()
返回當(dāng)前異常對(duì)象的完整類名+病態(tài)信息。
getMessage()
返回的是創(chuàng)建Throwable傳入的字符串信息唯咬。
printStackTrace()
打印異常的棧信息纱注。
比如以下代碼:
public class LoginTool {
/// 登錄時(shí)拋出異常
public void login(String user, String pwd) throws CustomException {
if (user.length() == 0 || pwd.length() == 0) {
/// 當(dāng)賬號(hào)或者密碼為空時(shí),就拋出異常
throw new CustomException("賬號(hào)或密碼為空胆胰,請(qǐng)重新輸入后狞贱,在點(diǎn)擊登錄");
} else {
System.out.println("登錄成功哦");
}
}
}
// 在處理異常時(shí),可以直接直接捕獲異常進(jìn)行處理
public static void main(String[] args) { /// 直接將異常拋給jvm虛擬機(jī)處理
LoginTool loginTool = new LoginTool();
try {
loginTool.login("sey", "");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace(); /// 打印異常拋出的堆棧信息
System.out.println(e.getMessage());
}
}
/// 也可以根據(jù)情況將異常繼續(xù)往上拋出, 在方面聲明后面throws CustomException
public static void main(String[] args) throws CustomException { /// 直接將異常拋給jvm虛擬機(jī)處理
LoginTool loginTool = new LoginTool();
loginTool.login("sey", "111");
}
java中一般異常和運(yùn)行時(shí)異常的區(qū)別:
Java提供了兩類主要的異常:runtime exception和checked exception蜀涨。checked
異常也就是我們經(jīng)常遇到的IO異常瞎嬉,以及SQL異常都是這種異常。對(duì)于這種異常厚柳,
JAVA編譯器強(qiáng)制要求我們必需對(duì)出現(xiàn)的這些異常進(jìn)行catch氧枣。所以,面對(duì)這種異常
不管我們是否愿意别垮,只能自己去寫一大堆catch塊去處理可能的異常便监。
但是另外一種異常:runtime exception,也稱運(yùn)行時(shí)異常碳想,我們可以不處理
茬贵。當(dāng)出現(xiàn)這樣的異常時(shí),總是由虛擬機(jī)接管移袍。比如:我們從來沒有人去處理過
NullPointerException異常解藻,它就是運(yùn)行時(shí)異常,并且這種異常還是最常見的異
常之一葡盗。
出現(xiàn)運(yùn)行時(shí)異常后螟左,系統(tǒng)會(huì)把異常一直往上層拋,一直遇到處理代碼觅够。如果
沒有處理塊胶背,到最上層,如果是多線程就由Thread.run()拋出喘先,如果是單線程就
被main()拋出钳吟。拋出之后,如果是線程窘拯,這個(gè)線程也就退出了红且。如果是主程序拋
出的異常坝茎,那么這整個(gè)程序也就退出了。運(yùn)行時(shí)異常是Exception的子類暇番,也有一
般異常的特點(diǎn)嗤放,是可以被Catch塊處理的。只不過往往我們不對(duì)他處理罷了壁酬。也就
是說次酌,你如果不對(duì)運(yùn)行時(shí)異常進(jìn)行處理,那么出現(xiàn)運(yùn)行時(shí)異常之后舆乔,要么是線程
中止岳服,要么是主程序終止。
如果不想終止希俩,則必須撲捉所有的運(yùn)行時(shí)異常派阱,決不讓這個(gè)處理線程退出。
隊(duì)列里面出現(xiàn)異常數(shù)據(jù)了斜纪,正常的處理應(yīng)該是把異常數(shù)據(jù)舍棄,然后記錄日志文兑。
不應(yīng)該由于異常數(shù)據(jù)而影響下面對(duì)正常數(shù)據(jù)的處理盒刚。在這個(gè)場(chǎng)景這樣處理可能是
一個(gè)比較好的應(yīng)用,但并不代表在所有的場(chǎng)景你都應(yīng)該如此绿贞。如果在其它場(chǎng)景因块,
遇到了一些錯(cuò)誤,如果退出程序比較好籍铁,這時(shí)你就可以不太理會(huì)運(yùn)行時(shí)異常涡上,或
者是通過對(duì)異常的處理顯式的控制程序退出。
- finally關(guān)鍵字
finally 塊拒名;
finally塊的 使用前提是必須要存在try塊才能使用吩愧。
finally塊的代碼在任何情況下都會(huì)執(zhí)行的,除了jvm退出的情況增显。
finally非常適合做資源釋放的工作雁佳,這樣子可以保證資源文件在任何情況下都 會(huì)被釋放。
try塊的三種組合方式:
第一種: 比較適用于有異常要處理同云,但是沒有資源要釋放的糖权。
try{
可能發(fā)生異常的代碼
}catch(捕獲的異常類型 變量名){
處理異常的代碼
}
第二種:比較適用于既有異常要處理又要釋放資源的代碼。
try{
可能發(fā)生異常的代碼
}catch(捕獲的異常類型 變量名){
處理異常的代碼
}finally{
釋放資源的代碼;
}
第三種: 比較適用于內(nèi)部拋出的是運(yùn)行時(shí)異常炸站,并且有資源要被釋放星澳。
try{
可能發(fā)生異常的代碼
}finally{
釋放資源的代碼;
}
比如下面代碼
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import javax.net.ssl.SSLContext;
public class FinallyDemo {
public void demo() throws IOException {
/// 在任何一個(gè)空閑的端口上創(chuàng)建一個(gè)套接字
ServerSocket serverSocket = new ServerSocket();
try {
Socket socket = serverSocket.accept();
} catch (Exception e) {
// TODO: handle exception
System.out.println("socket失敗");
} finally {
serverSocket.close();
System.out.println("關(guān)閉成功");
}
}
}
這段代碼創(chuàng)建了一個(gè)套接字,并調(diào)用 accept 方法旱易。在退出該方法之前禁偎,您必須關(guān)閉此套接字腿堤,以避免資源漏洞。為了完成這一任務(wù)
finally 塊確保 close 方法總被執(zhí)行届垫,而不管 try 塊內(nèi)是否發(fā)出異常释液。因此,可以確保在退出該方法之前總會(huì)調(diào)用 close 方法装处。這樣您就可以確信套接字被關(guān)閉并且您沒有泄漏資源误债。在此方法中不需要再有一個(gè) catch 塊。在第一個(gè)示例中提供 catch 塊只是為了關(guān)閉套接字妄迁,現(xiàn)在這是通過 finally 關(guān)閉的寝蹈。如果您確實(shí)提供了一個(gè) catch 塊,則 finally 塊中的代碼在 catch 塊完成以后執(zhí)行登淘。
finally 塊必須與 try 或 try/catch 塊配合使用箫老。此外铜异,不可能退出 try 塊而不執(zhí)行其 finally 塊严肪。如果 finally 塊存在,則它總會(huì)執(zhí)行叠赦。(無論從那點(diǎn)看流妻,這個(gè)陳述都是正確的牲蜀。有一種方法可以退出 try 塊而不執(zhí)行 finally 塊。如果代碼在 try 內(nèi)部執(zhí)行一條 System.exit(0); 語句绅这,則應(yīng)用程序終止而不會(huì)執(zhí)行 finally 執(zhí)行涣达。另一方面,如果您在 try 塊執(zhí)行期間撥掉電源证薇,finally 也不會(huì)執(zhí)行度苔。)