Java007-物件導向(多型)

姚根深發表於2019-01-19

多 態(物件導向特徵之一):
函式本身就具備多型性,某一種事物有不同的具體的體現。

體現:父類引用或者介面的引用指向了自己的子類物件。//Animal a = new Cat();
多型的好處:提高了程式的擴充套件性。
多型的弊端:當父類引用指向子類物件時,雖然提高了擴充套件性,但是隻能訪問父類中具備的方法,不可以訪問子類中特有的方法。(前期不能使用後期產生的功能,即訪問的侷限性)
多型的前提:
1:必須要有關係,比如繼承、或者實現。
2:通常會有覆蓋操作。

多型的出現思想上也做著變化:以前是建立物件並指揮物件做事情。有了多型以後,我們可以找到物件的共性型別,直接操作共性型別做事情即可,這樣可以指揮一批物件做事情,即通過操作父類或介面實現。

class 畢姥爺{
void 講課(){
System.out.println(“企業管理”);
}
void 釣魚(){
System.out.println(“釣魚”);
}
}
class 畢老師 extends 畢姥爺{
void 講課(){
System.out.println(“JAVA”);
}
void 看電影(){
System.out.println(“看電影”);
}
}
class {
public static void main(String[] args) {
畢姥爺 x = new 畢老師(); //畢老師物件被提升為了畢姥爺型別。
//x.講課();
//x.看電影(); //錯誤.
畢老師 y = (畢老師)x; //將畢姥爺型別強制轉換成畢老師型別。
y.看電影();//在多型中,自始自終都是子類物件在做著型別的變化。
}

}

如果想用子類物件的特有方法,如何判斷物件是哪個具體的子類型別呢?
可以可以通過一個關鍵字 instanceof ;//判斷物件是否實現了指定的介面或繼承了指定的類

格式:<物件 instanceof 型別> ,判斷一個物件是否所屬於指定的型別。
Student instanceof Person = true;//student繼承了person類

多型在子父類中的成員上的體現的特點:
1,成員變數:在多型中,子父類成員變數同名。
在編譯時期:參考的是引用型變數所屬的類中是否有呼叫的成員。(編譯時不產生物件,只檢查語法錯誤)
執行時期:也是參考引用型變數所屬的類中是否有呼叫的成員。
簡單一句話:無論編譯和執行,成員變數參考的都是引用變數所屬的類中的成員變數。
再說的更容易記憶一些:成員變數 — 編譯執行都看 = 左邊。
2,成員函式。
編譯時期:參考引用型變數所屬的類中是否有呼叫的方法。
執行事情:參考的是物件所屬的類中是否有呼叫的方法。
為什麼是這樣的呢?因為在子父類中,對於一模一樣的成員函式,有一個特性:覆蓋。
簡單一句:成員函式,編譯看引用型變數所屬的類,執行看物件所屬的類。
更簡單:成員函式 — 編譯看 = 左邊,執行看 = 右邊。
3,靜態函式。
編譯時期:參考的是引用型變數所屬的類中是否有呼叫的成員。
執行時期:也是參考引用型變數所屬的類中是否有呼叫的成員。
為什麼是這樣的呢?因為靜態方法,其實不所屬於物件,而是所屬於該方法所在的類。
呼叫靜態的方法引用是哪個類的引用呼叫的就是哪個類中的靜態方法。

簡單說:靜態函式 — 編譯執行都看 = 左邊。

——java.lang.Object
Object:所有類的直接或者間接父類,Java認為所有的物件都具備一些基本的共性內容,這些內容可以不斷的向上抽取,最終就抽取到了一個最頂層的類中的,該類中定義的就是所有物件都具備的功能。

具體方法:
1,boolean equals(Object obj):用於比較兩個物件是否相等,其實內部比較的就是兩個物件地址。
而根據物件的屬性不同,判斷物件是否相同的具體內容也不一樣。所以在定義類時,一般都會複寫equals方法,建立本類特有的判斷物件是否相同的依據。
public boolean equals(Object obj){
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return this.age == p.age;
}
2,String toString():將物件變成字串;預設返回的格式:類名@雜湊值 = getClass().getName() + `@` + Integer.toHexString(hashCode())
為了物件對應的字串內容有意義,可以通過複寫,建立該類物件自己特有的字串表現形式。
public String toString(){
return “person : “+age;
}
3,Class getClass():獲取任意物件執行時的所屬位元組碼檔案物件。
4,int hashCode():返回該物件的雜湊碼值。支援此方法是為了提高雜湊表的效能。

通常equals,toString,hashCode,在應用中都會被複寫,建立具體物件的特有的內容。

內部類:如果A類需要直接訪問B類中的成員,而B類又需要建立A類的物件。這時,為了方便設計和訪問,直接將A類定義在B類中。就可以了。A類就稱為內部類。內部類可以直接訪問外部類中的成員。而外部類想要訪問內部類,必須要建立內部類的物件。

class Outer{
int num = 4;
class Inner {
void show(){
System.out.println(“inner show run “+num);
}
}
public void method(){
Inner in = new Inner();//建立內部類的物件。
in.show();//呼叫內部類的方法。
}

}

當內部類定義在外部類中的成員位置上,可以使用一些成員修飾符修飾 private、static。
1:預設修飾符。
直接訪問內部類格式:外部類名.內部類名 變數名 = 外部類物件.內部類物件;
Outer.Inner in = new Outer.new Inner();//這種形式很少用。
但是這種應用不多見,因為內部類之所以定義在內部就是為了封裝。想要獲取內部類物件通常都通過外部類的方法來獲取。這樣可以對內部類物件進行控制。
2:私有修飾符。
通常內部類被封裝,都會被私有化,因為封裝性不讓其他程式直接訪問。
3:靜態修飾符。
如果內部類被靜態修飾,相當於外部類,會出現訪問侷限性,只能訪問外部類中的靜態成員。
注意;如果內部類中定義了靜態成員,那麼該內部類必須是靜態的。

內部類編譯後的檔名為:“外部類名$內部類名.java”;

為什麼內部類可以直接訪問外部類中的成員呢?
那是因為內部中都持有一個外部類的引用。這個是引用是 外部類名.this
內部類可以定義在外部類中的成員位置上,也可以定義在外部類中的區域性位置上。
當內部類被定義在區域性位置上,只能訪問區域性中被final修飾的區域性變數。

匿名內部類:沒有名字的內部類。就是內部類的簡化形式。一般只用一次就可以用這種形式。匿名內部類其實就是一個匿名子類物件。想要定義匿名內部類:需要前提,內部類必須繼承一個類或者實現介面。

匿名內部類的格式:new 父類名&介面名(){ 定義子類成員或者覆蓋父類方法 }.方法。

匿名內部類的使用場景:
當函式的引數是介面型別引用時,如果介面中的方法不超過3個。可以通過匿名內部類來完成引數的傳遞。

其實就是在建立匿名內部類時,該類中的封裝的方法不要過多,最好兩個或者兩個以內。

//面試
//1
new Object(){
void show(){
System.out.println(“show run”);
}
}.show();
//2
Object obj = new Object(){
void show(){
System.out.println(“show run”);
}
};
obj.show();

1和2的寫法正確嗎?有區別嗎?說出原因。
寫法是正確,1和2都是在通過匿名內部類建立一個Object類的子類物件。
區別:
第一個可是編譯通過,並執行。
第二個編譯失敗,因為匿名內部類是一個子類物件,當用Object的obj引用指向時,就被提升為了

Object型別,而編譯時檢查Object類中是否有show方法,所以編譯失敗。

class InnerClassDemo6 {
+(static)class Inner{
void show(){}
}
public void method(){
this.new Inner().show();//可以
}
public static void main(String[] args) {//static不允許this
This.new Inner().show();//錯誤,Inner類需要定義成static
}

}

interface Inter{
void show();
}
class Outer{//通過匿名內部類補足Outer類中的程式碼。
public static Inter method(){
return new Inter(){
public void show(){}
};
}
}
class InnerClassDemo7 {
public static void main(String[] args) {
Outer.method().show();
/*
Outer.method():意思是:Outer中有一個名稱為method的方法,而且這個方法是靜態的。
Outer.method().show():當Outer類呼叫靜態的method方法運算結束後的結果又呼叫了show方法,意味著:method()方法運算完一個是物件,而且這個物件是Inter型別的。
*/
function (new Inter(){
public void show(){}
}); //匿名內部類作為方法的引數進行傳遞。
}
public static void function(Inter in){
in.show();
}

}

相關文章