java面向對象--繼承與多態

可以為一個變異單元中的每個類創建一個main方法,只有命令行所調用的那個類的main方法才會被調用,這樣方便進行單元測試。
繼承時,一般將所有的數據成員都指定為private,將所有的方法指定為public。
當創建一個子類的對象時,該對象內部包含了一個父類的子對象(subobject??)。這個對象和用父類直接創建的對象是一樣的。
關鍵字super并不是一個對象的引用,因為不能將super賦值給另外一個對象變量。super只是一個只是編譯器調用直接父類成員變量的特殊關鍵字。有兩種用途:一是調用父類的方法;二是調用父類的構造器。
如果父類構造器為無參構造器,子類構造器中可以不用寫調用父類構造器的語句,編譯器會自動加上。但是如果父類構造器有參數時,在子類構造器中必須顯式的通過super(arg)調用父類的構造器,否則會報錯。
子類可以override父類方法,也可以overload父類的方法。
所有的override都使用@Override注解,可以防止不想重載時而意外的進行了重載。
重寫(Override)
重寫是子類對父類允許訪問的方法的實現過程進行重新編寫。好處在于子類可以根據需要,定義特定于自己的行為。
當父類中的方法被覆蓋了后,除非用super關鍵字,否則就無法再調用父類中的方法。
重寫規則:兩同兩小一大。
方法名、參數列表必須相同;返回值類型和拋出的異常更小或相等;訪問權限更大或相等。
聲明為final的方法不能被重寫;
聲明為static的方法不能被重寫,但是能夠被再次聲明;
重寫的方法能夠拋出任何非強制異常,不能拋出新的或更廣泛的強制性異常;
構造方法不能被重寫;
父類的成員方法只能被它的子類重寫,如果不能繼承一個方法,則不能重寫這個方法;
子類和父類在同一個包中,聲明為private和final的方法不可被子類重寫;
子類和父類不在同一個包中,子類只能重寫父類的聲明為public和protected的非final方法;
被覆蓋的方法不能為static,因為靜態方法是在編譯的時候把靜態方法和類的引用類型進行匹配。

組合和繼承
組合是”has-a”的關系,在新類中嵌入一個現有類的private對象,新類的用戶看到的是為新類所定義的接口,而不能看到嵌入對象的方法。
extend關鍵字的英文意思是擴展,表明子類對父類的擴展,子類是一種特殊的父類。
繼承是”is-a”的關系,使用某個現有類,并開發一個它的特殊版本。通常使用的場景:
  1. 子類需要額外增加屬性,而不僅僅是屬性值的改變。
  2. 子類需要增加自己獨有的行為方式(包括增加新的方法或重寫父類的方法)。
只有必須向上轉型時才用繼承,否則優先考慮使用組合。

向上轉型
為什么需要?
子類不僅是子類的類型,而且也是父類的類型。向上轉型是從一個較專用類型向較通用類型轉換,一般比較安全,唯一可能反生的事情是接口變小丟失子類對父類擴展的方法。因為引用變量在編譯階段只能調用其編譯時類型所具有的方法,否則會報錯。

final關鍵字:一旦(在初始化過程中)被設置為初始值之后,就不能再改變。

final數據:static final編譯時期常量,全用大寫字母表示,單詞間用下劃線’_’分割。

  對于基本類型,final使數字恒定不變;而對于對象引用,final使引用恒定不變,但引用的對象可以發生改變。

  空白final:被聲明為final但又未給定初值的成員變量。需確保在使用前初始化。

  final參數:無法在方法中更改參數引用所指向的對象。

  final方法:確保在繼承中方法行為保持不變,并且不會被覆蓋或修改。

類中所有的 private 方法都隱式地是 final 的。

final類:不允許做任何變動,沒有子類,所以方法也隱式地為final的。

不可變類(immutable):創建該類的實例之后,該實例的屬性是不可變的。如果不可變類包含引用類型的屬性,可以在內部重新構建一個一模一樣的對象賦值給引用,使引用脫離外部影響。

多態
相同類型的父類引用變量,執行同一個方法時呈現出不同的行為,這就是多態。
“封裝”通過合并特征和行為來創建新的數據類型?!笆迪忠亍痹蟯ü附謁接謝涌諍褪迪址擲肟?。而多態的作用則是消除類型之間的耦合關系,將多種子類型視為同一父類型進行處理(父類型的引用變量可以引用不同子類型的對象),這樣同一份代碼可以毫無差別地運行在這些不同子類型上,不用為每一個子類型重復定義相同邏輯的處理方法。
多態用父類型引用調用相應的方法,如何確定是哪個具體子類型呢?
綁定指的是將一個方法的調用與方法的主體關聯起來java中,綁定分為靜態綁定和動態綁定(dynamic binding),或者叫做前期綁定(early binding)和后期綁定(late binding)。

靜態綁定:在程序執行前方法已經被綁定(也就是說在編譯過程中就已經知道這個方法到底是哪個類中),此時由編譯器或其它連接程序實現。

在java中可以簡單理解為程序編譯期的綁定,只有被final,static,private修飾的方法和構造方法是前期綁定的,由聲明的類型決定。
java的編譯過程是將java源文件編譯成字節碼(jvm可執行代碼,即.class文件)的過程,在這個過程中java是不與內存打交道的,編譯器會進行語法的分析,如果語法不正確就會報錯(比如編譯器只允許對象調用在類中聲明的函數)。
Java的運行過程是指jvm(java虛擬機)裝載字節碼文件并解釋執行,在這個過程才創立內存空間,執行java程序。

動態綁定:在運行時根據對象的類型進行綁定。之所以存在動態綁定,就是因為有些方法需要實例化對象后才能確定是哪個類的。
若一種語言實現了后期綁定,必須提供一些機制,可在運行期間判斷對象的類型,并分別調用適當的方法。也就是說,編譯器一直不知道對象的類型,但方法調用機制能找到正確的方法主體并加以調用。
動態綁定的過程:
虛擬機提取對象的實際類型的方法表(虛擬機預先為每個類創建的表,列出了所有方法的簽名,以后方法調用時就無需搜索,只要查表就性);虛擬機搜索方法簽名;調用方法。
動態綁定的特性:無需對現存的方法代碼進行重新編譯就可以對程序進行擴展。
動態綁定的典型發生在父類和子類的轉換聲明之下:Parent p = new Child();
注意:運行時(動態)綁定針對的范疇只是對象的方法,類中的成員變量(實例變量和類變量)是一般意義上的靜態綁定,由編譯器解析,只能訪問引用變量類型所具有的屬性。所以在向上轉型后,父類的引用調用哪個子類型的方法由子類型對象決定,而訪問對象屬性時,系統總是訪問它編譯時類所定義的屬性,即由向上造型后的父類型引用決定(子類對父類成員變量的隱藏)。
重載的方法簽名是完全不同的,所以靜態綁定就可以確定到底是哪個方法了;而重寫的方法簽名是可以和超類一樣的,需要實例化對象之后才能確定是哪個類中的方法。
super.getClass().getName() //返回當前子類的類名


package demo3;class Super {    public int field = 0;    public int getField() {        return field;
    }
}class Sub extends Super {    public int field = 1;    public int getField() {        return field;
    }    public int getSuperField() {        return super.field;
    }
}public class FieldAccess {    public static void main(String[] args) {
        Super sup = new Sub(); // Upcast
        System.out.println("sup.field = " + sup.field + ", sup.getField() = " + sup.getField());
        Sub sub = new Sub();
        System.out.println("sub.field = " + sub.field + ", sub.getField() = " + sub.getField()+ ", sub.getSuperField() = " + sub.getSuperField());
    }
}/** Output: sup.field = 0, sup.getField() = 1 sub.field = 1, sub.getField() = 1,
* sub.getSuperField() = 0*/// :~


向下轉型
父類型的引用變量轉向更具體的子類型,不安全,有可能會導致ClassCastExecption。轉型之前先用instanceof 關鍵字判斷一下。
instanceof:is a runtime check,判斷前者引用變量是否是后者實現類或接口的實例,通常instanceof前后的操作數有實現或繼承關系,否則在編譯時就會出錯,而不會等運行時再返回false,效率更高。
new Date() instanceof String;// Incompatible conditional operand types Date and String

super和this的區別
1)super(參數):子類調用父類的某一個構造函數(應該為子類構造函數中的第一條語句) 
2)this(參數):調用本類中重載的構造函數(應該為構造函數中的第一條語句)
3)super: 基類與派生類中有相同成員定義時,用來訪問當前對象的直接父類中的成員(即訪問直接父類中被隱藏/覆蓋的成員數據或方法)。如:super.屬性名,super.方法名。
4)this:它代表當前對象的引用(如果函數的形參與類的屬性同名,這時需用this來指明對象的屬性)
5)調用super()必須寫在子類構造方法的第一行,否則編譯不通過。每個子類構造方法的第一條語句,都是隱含地調用super()。
6)盡管可以用this調用一個構造器,但卻不能調用兩個。
7)this和super不能同時出現在一個構造函數里面,因為this必然會調用其它的構造函數,其它的構造函數必然也會有super語句的存在,所以在同一個構造函數里面有相同的語句,就失去了語句的意義,編譯器也不會通過。
8)this()和super()都指的是對象,所以都不可以在static環境中使用。包括static變量,static方法和static語句塊。
9)從本質上講,this是一個指向本對象的指針, 然而super是一個Java關鍵字。

以上皆為個人理解,如有錯誤之處,歡迎留言指正。


來源:博客園

上一篇: java面向對象--對象初始化

下一篇: 新手入門:寫Java程序的三十個基本規則

分享到: 更多
欢乐生肖投注技巧 广东十一选五计划软件怎么买? 天津时时开奖趋势 玩通比牛牛有什么技巧 皇家国际百人炸金花 通比牛牛亿元赌博案 竞彩混合投注比分 最科学的买彩票稳赚不赔 第90香港马会36码 时时彩超级精准计划群 三期必開一肖 3d彩票稳赚不亏的方法 七乐彩中奖规则及奖金 七星彩最准确十专家 大乐透中奖规则表 体彩稳赚不赔啊