多態(tài)
概述:某一個事物,在不同時刻表現(xiàn)出來的不同狀態(tài)。
我們來舉例說明:
- 貓是貓,狗是狗,貓和狗都是動物。
- 水在不同環(huán)境下的狀態(tài)不同(液體,固體,氣態(tài))
那么使用多態(tài)的前提是什么呢?
- 要有繼承關系。
- 要有方法重寫。
//其實沒有也是可以的,但是如果沒有這個就沒有意義。
Animal c = new Cat();
c.show();
Animal d = new Dog();
d.show();
- 要有父類引用指向子類對象
父 f = new 子();
下面我們用代碼來體現(xiàn)
class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("function Fu");
}
}
class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() {
System.out.println("function Zi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
//要有父類引用指向子類對象。
//父 f = new 子();
Fu f = new Zi();
System.out.println(f.num);
//找不到符號
//System.out.println(f.num2); f.show();
//找不到符號
//f.method(); f.function();
}
}
下面我們用代碼來體現(xiàn)
- 成員變量
- 編譯看左邊,運行看左邊
- 構(gòu)造方法
- 子類的構(gòu)造都會默認訪問父類構(gòu)造
- 成員方法
- 編譯看左邊,運行看右邊
- 靜態(tài)方法
- 編譯看左邊,運行看左邊
- 所以靜態(tài)方法不能算方法的重寫
學了這么多我們應該了解下多態(tài)的好處:
- 提高了代碼的維護性(繼承保證)
- 提高了代碼的擴展性(由多態(tài)保證)
多態(tài)有好處,當然也有弊端了不能使用子類的特有功能。 那么我們?nèi)绾尾拍茉L問子類的特有功能呢?多態(tài)中的轉(zhuǎn)型 怎么用呢?
- 創(chuàng)建子類對象調(diào)用方法即可。(可以,但是很多時候不合理。而且,太占內(nèi)存了)
- 把父類的引用強制轉(zhuǎn)換為子類的引用。(向下轉(zhuǎn)型)
關于對象間的轉(zhuǎn)型問題:
- 向上轉(zhuǎn)型
- 從子到父
- 父類引用指向子類對象
- Fu f = new Zi();
- 向下轉(zhuǎn)型
- 從父到子
- 父類引用轉(zhuǎn)為子類對象
- Zi z = (Zi)f; //要求該f必須是能夠轉(zhuǎn)換為Zi的。
class Fu {
public void show() {
System.out.println("show fu");
}
}
class Zi extends Fu {
public void show() {
System.out.println("show zi");
}
public void method() {
System.out.println("method zi");
}
}
class DuoTaiDemo3 {
public static void main(String[] args) {
//測試
Fu f = new Zi();
f.show();
f.method();
//多態(tài)的弊端不能使用子類的特有功能。
}
}
//所以輸出結(jié)果是:show zi
//關于向下轉(zhuǎn)型,我們能夠把子類的對象賦值給父類,
//所以我們也可以把父類的引用賦值給子類的引用
//怎么使用呢,只要在上面例子的基礎上稍做修改
Son z = (Son) f;
z.show();
z.method();
//輸出結(jié)果就變了:show zi //method zi
內(nèi)部類
- 概述:把類定義在其他類的內(nèi)部,這個類就被稱為內(nèi)部類。
舉例:在類A中定義了一個類B,類B就是內(nèi)部類。
-
內(nèi)部的訪問特點:
- 內(nèi)部類可以直接訪問外部類的成員,包括私有。
- 外部類要訪問內(nèi)部類的成員,必須創(chuàng)建對象。
-
內(nèi)部類位置
- 成員位置:在成員位置定義的類,被稱為成員內(nèi)部類。
- 局部位置:在局部位置定義的類,被稱為局部內(nèi)部類。
class Outer {
private int num = 10;
//成員位置,成員內(nèi)部類
class Inner {
}
public void method() {
//局部位置,局部內(nèi)部類
class Inner { }
}
}
成員內(nèi)部類
我們了解了成員內(nèi)部類,那么如何直接訪問內(nèi)部類的成員。外部類名.內(nèi)部類名 對象名 = 外部類對象.內(nèi)部類對象;
class Outer {
private int num = 10;
class Inner {
public void show() {
System.out.println(num);
}
}
}
class InnerClassDemo {
public static void main(String[] args) {
//需求:我要訪問Inner類的show()方法
//Inner i = new Inner();
//i.show(); 這樣訪問不到
//格式:外部類名.內(nèi)部類名 對象名 = 外部類對象.內(nèi)部類對象;
Outer.Inner oi = new Outer().new Inner();
oi.show();
}
}
上面學習了成員內(nèi)部類的使用,但是一般來說,在實際開發(fā)中是不會這樣使用的。因為一般內(nèi)部類就是不讓外界直接訪問的。
- 成員內(nèi)部的常見修飾符
- private 為了保證數(shù)據(jù)的安全性
- static 為了讓數(shù)據(jù)訪問更方便
- 被靜態(tài)修飾的成員內(nèi)部類只能訪問外部類的靜態(tài)成員
- 內(nèi)部類被靜態(tài)修飾后的方法
- 靜態(tài)方法
- 非靜態(tài)方法
class Outer { private static int num = 100; //內(nèi)部類用靜態(tài)修飾是因為內(nèi)部類可以看出是外部類的成員 public static class Inner { public void show() { System.out.println(num); } public static void show2() { System.out.println(num); } }}class InnerClassDemo { public static void main(String[] args) { //成員內(nèi)部類被靜態(tài)修飾后的訪問方式是: Outer.Inner.show2(); }}
局部內(nèi)部類
- 可以直接訪問外部類的成員
- 在局部位置,可以創(chuàng)建內(nèi)部類對象,通過對象調(diào)用內(nèi)部類方法,來使用局部內(nèi)部類功能
class Outer {
private int num = 10;
public void method() {
//int num2 = 20;
final int num2 = 20;
class Inner {
public void show() {
System.out.println(num);
//從內(nèi)部類中訪問本地變量num2; 需要被聲明為最終類型
System.out.println(num2);//20
}
}
//System.out.println(num2);
Inner i = new Inner(); i.show();
}
}
class InnerClassDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method(); //結(jié)果是:10 20
}
}
局部內(nèi)部類訪問局部變量的注意事項:
- 局部內(nèi)部類訪問局部變量必須用final修飾
- 原因:局部變量是隨著方法的調(diào)用而調(diào)用,隨著調(diào)用完畢而消失。而堆內(nèi)存的內(nèi)容并不會立即消失。所以,我們加final修飾。加入final修飾后,這個變量就成了常量。既然是常量。你消失了。在內(nèi)存中存儲的是數(shù)據(jù)20,所以,還是有數(shù)據(jù)在使用。
匿名內(nèi)部類
- 匿名內(nèi)部類就是內(nèi)部類的簡化寫法。
- 前提:存在一個類或者接口
- 這里的類可以是具體類也可以是抽象類。 - 格式:
- new 類名或者接口名() {重寫方法;} - 本質(zhì):
- 是一個繼承了類或者實現(xiàn)了接口的子類匿名對象
interface Inter {
public abstract void show();
public abstract void show2();
}
class Outer {
public void method() {
//一個方法的時候 /*
new Inter() { public void show() { System.out.println("show"); }
}.show(); */
//二個方法的時候 /* new Inter() { public void show()
{ System.out.println("show"); }
public void show2() { System.out.println("show2"); } }.show(); new Inter() { public void show() { System.out.println("show"); } public void show2() { System.out.println("show2"); } }.show2(); */
//如果我是很多個方法,就很麻煩了
//那么,我們有沒有改進的方案呢?
Inter i = new Inter() { //多態(tài)
public void show() { System.out.println("show"); }
public void show2() { System.out.println("show2");}
};
i.show();
i.show2();
}
}
class InnerClassDemo {
public static void main(String[] args) {
Outer o = new Outer();
o.method();
//輸出結(jié)果:show show2 }
}