final
final可修飾成員變量,局部變量,形參,類,方法
static可修飾屬性,方法,類,靜態代碼塊
被final修飾後的標識符叫做常量(常量一般用大寫字母表示),且內存地址不能再變了
被final修飾後必須賦初值,且只有一次機會
public final int a = 12;
public final StringBuilder sb = new StringBuilder();
sb.append("zhangaoqi");
sb.append("zaq");
System.out.println(sb.toString());//輸出 zhangaoqizaq
上面的sb可以被修改,很神奇,這是因爲他改變的不是StringBuilder,而是StringBuilder裏的內容
- 靜態常量(static final):不創建對象就能訪問,且值不能改變
public static final int a = 1;
- 被final修飾的方法在繼承時不能再被重寫
public static fianl void foo() {
System.out.println("a");
}
- final修飾類,代表這個類不能被繼承了,但這個類的對象能改變,只是這個類的結構不能被改變了
abstract
之前定義的類都爲普通類,之後會出現抽象類,外部類,內部類,匿名類,靜態內部類。
abstract可以修飾類,方法
普通的類沒有能力承載抽象方法,抽象類能承載它
abstract修飾的類,實際不能單獨存在,單獨拿出來沒有意義,他修飾的方法,沒有執行過程,只是知道有這個方法
打個比方:定義一個塑料玩具類,玩具一定有一個玩的方法,但是每個玩具的玩法都不同。所以再沒有確定這個塑料玩具是啥之前根本不知道它的方法怎麼執行,但是你一定確定他可以玩,所以會有一個玩的方法。這個方法,塑料玩具類可以實現它,但是實現了並沒有意義。每個生產廠商再繼承它時都需要從寫它,所以在料玩具類中沒有必要去實現它,但是一定要聲明他。如果誰繼承了塑料玩具類,那麼他必須要實現這個方法
所以abstract修飾的方法剛好和final修飾的方法反過來了,與final構成了反義詞,abstract修飾的方法必修被重寫,但final修飾的方法一定不能被重寫,所以abstract修飾修飾的類一定要被繼承
代碼實現一下
父類(塑料玩具類)
public abstract class PlasticToy {
public abstract void play();//聲明一個抽象方法,沒必要實現這個方法,但他的子類必須實現它
}
子類(玩具廠商類)
public class PlasticGun extends PlasticToy {
@Override
public void play() {
System.out.println("biubiubiu");
}
}
其實,子類必須實現父類的抽象方法,這句話不對。如果子類也有能力承載抽象方法就可以不用實現父類中的抽象方法(子類也是抽象類),這時子類存在的意義也就是讓別人來繼承它
抽象類中可以有構造方法,但是他不能創建對象
抽象類的構造方法用來定義子類中必須要對這個類的一些屬性初始化。
抽象類的構造方法爲啥不能用來創建對象?
反例來證一下,如果可以創建對象,那麼它就可以通過對象來調用抽象類中的抽象方法了,但是他沒有方法體,根本不能執行,所以不能創建對象。
從原理上說,是因爲創建對象時要把每個方法都放到方法棧中,現在拿到了一個抽象方法,他沒有方法體,根本不知道他佔多大內存,運行行計數器指向哪,所以沒辦法把他放入方法棧,所以不能創建對象
對比一下普通類和抽象類
普通類可以放普通方法,屬性,靜態變量,常量,可以有構造方法,能創建對象,不能放抽象方法
抽象類可以放普通方法,抽象方法,可以有構造方法但是不能創建對象
抽象類存在的價值讓別人繼承,抽象方法存在的價值讓別人是實現,抽象類就是規定所有子類的模板
匿名類
匿名類(也叫匿名內部類):匿名類會被默認爲這個父類或者接口的子類或實現類如。
如果抽象類非要創建對象那也可以,可以創建一個他的匿名子類對象,這個匿名類繼承父類且重寫父類中的抽象方法,且這個匿名對象只能用一次
場景類
public class Main {
public static void main(String[] args) {
PlasticToy toy = new PlasticToy()/*這個花括號裏的東西就叫做匿名類*/ {
@Override
public void play() {
}
};
}
}