1、多态
概述
- 面向對象的三大特征:封裝、繼承、多态
- 多态的形式:
父類 對象名稱 = new 子類構造器; 接口 對象名稱 = new 實作類構造器; 父類類型範圍 > 子類類型範圍
- 相同類型的變量調用同一個行為,在不同狀态下可以表現出不同的特征
- 使用前提:
- 必須存在繼承或實作關系
- 存在父類類型的變量引用子類類型的對象
- 存在方法重寫
- 識别技巧:
- 對于方法調用:編譯看左,運作看右
- 對于變量的調用:編譯看左,運作也看左
public class PolymorphicDemo { public static void main(String[] args) { //多态:父類 對象名稱 = new 子類構造器; Animal dog = new Dog(); Animal rabbit = new Rabbit(); //調用方法 dog.run(); //狗類run方法 rabbit.run(); //兔類run方法 //調用變量 System.out.println(dog.name); //動物類 System.out.println(rabbit.name); //動物類 } } class Animal{ public String name = "動物類"; public void run(){ System.out.println("動物類run方法"); } } class Dog extends Animal{ public String name = "狗類"; @Override public void run() { System.out.println("狗類run方法"); } } class Rabbit extends Animal{ public String name = "兔類"; @Override public void run() { System.out.println("兔類run方法"); } }
多态的優劣勢
優勢:
- 在多态形式下,右邊對象可以實作元件化解耦,右邊的對象可以随意的切換 後續業務功能代碼可以不用修改,而功能可以産生變化便于擴充和維護
- 父類類型作為方法形參,傳遞子類對象給方法,進行不同的調用,展現出多态的擴充性
劣勢:
- 多态形式下編譯看左邊,是以無法調用子類獨有功能
多态的類型轉換
引用類型自動類型轉換
- 子類對象或者子類類型的變量可以直接自動類型轉換給父類類型的變量
- 并沒有解決多态的劣勢,無法調用子類的特有功能
引用類型強制類型轉換
- 父類對象或者父類類型的變量指派給子類類型的變量必須進行強制類型轉換
- 格式:
子類名稱 對象名稱 = (子類名稱)父類對象或者父類類型的變量
-
強制轉換異常問題:原因是轉換前後對象類型不一緻
類型轉換異常:ClassCastException
- 建議進行引用類型強制轉換之前,先判斷對象的真實類型
public class PolymorphicDemo01 { public static void main(String[] args) { Animal animal = new Dog(); animal.run(); //狗子快跑 //animal.lookDoor(); // 多态下不能直接調用子類獨有功能——多态的劣勢 //先不進行判斷真是類型直接強轉(在知道真實類型的情況下) Dog dog = (Dog)animal; // 強制類型轉換成Dog類 dog.lookDoor(); //狗子看門 // 若不知道真實類型則可能出現類型轉換異常 Animal animal2 = new Cat(); // Dog dog2 = (Dog) animal2; // 貓類型轉成狗類型是以出錯 // 在進行引用類型強制轉換之前,先用instanceof判斷對象的真實類型: if(animal2 instanceof Dog){ // animal2真實類型真的是狗 Dog dog2 = (Dog) animal2; dog2.lookDoor(); //狗子看門 }else if(animal2 instanceof Cat){ // animal2真實類型是貓 Cat cat = (Cat) animal2; cat.catchMouse(); } } } //父類 class Animal{ public void run(){ System.out.println("動物都能跑"); } } //子類貓 class Cat extends Animal { @Override public void run(){ System.out.println("貓貓快跑"); } // 獨有功能 public void catchMouse(){ System.out.println("貓抓老鼠"); } } //子類狗 class Dog extends Animal { @Override public void run(){ System.out.println("狗子快跑"); } // 獨有功能 public void lookDoor(){ System.out.println("狗子看門"); } }
2、内部類
概述
- 定義在類裡面的類就是内部類
- 内部類可以提供更好的封裝性,内部類有更多的權限修飾符,封裝性有更多的控制
- 内部類的分類:
- 靜态内部類
- 執行個體内部類
- 局部内部類
- 匿名内部類
靜态内部類
- 用static修飾的内部類,屬于外部類本身是以會和外部類一起加載一次,隻有一份
- 類有的成分靜态内部類都具備,隻是位置在一個類中,與普通類基本沒差別
- 通路格式:
外部類名稱.内部類名稱
- 建立對象的格式:
外部類名稱.内部類名稱 對象名稱 = new 外部類名稱.内部類名稱
- 靜态内部類是否可以直接通路外部類的靜态成員? 可以的,外部類的靜态成員隻有一份是被共享的
- 靜态内部類是否可以直接通路外部類的執行個體成員? 不可以的,外部類的執行個體成員必須用外部類的對象通路
執行個體内部類
- 無static修飾的内部類,屬于外部類的每個對象,與對象一起加載
- 不能定義靜态成員,可以定義常量
- 執行個體内部類中通路所在外部類對象的格式:
- 建立對象的格式:
public class InnerClass { public static void main(String[] args) { // 外部類名稱.内部類名稱 對象名稱 = new 外部類構造器.new 内部類構造器; Outter.Inner inner = new Outter().new Inner(); inner.jump(); } } class Outter{ private int weight = 30; // 執行個體内部類:屬于外部類對象。 public class Inner { private int weight = 20; //可以定義常量 public static final String SCHOOL_NAME = "北大" ; public void jump() { int weight = 10; System.out.println(weight); // 10 System.out.println(this.weight); // 20 System.out.println(Outter.this.weight); // 30 } } }
- 執行個體内部類是否可以直接通路外部類的靜态成員?可以的,外部類的靜态成員可以被共享,隻有一份
- 執行個體内部類是否可以直接通路外部類的執行個體成員?可以的,執行個體内部類和外部類的執行個體成員都在外部類對象中
局部内部類
- 定義在方法中、構造器中、代碼塊中、for循環中的内部類
- 隻能定義執行個體成員,不能定義靜态成員
- 可以定義常量
匿名内部類
- 格式:
new 類名|接口|抽象類(形參){ 被重寫的方法 }
- 特點:
- 是沒有名字的内部類
- 會自動建立目前匿名内部類的一個對象傳回
- 匿名内部類傳回的對象類型相當于是繼承了目前所new的那個類型的子類
public class AnonymityDemo01 {
public static void main(String[] args) {
// Animal animal = new Cat();
// animal.run();
//匿名内部類
Animal animal = new Animal() {
@Override
public void run() {
System.out.println("貓跑得挺快");
}
};
animal.run();
}
}
//正常子類繼承父類後重寫方法,建立對象調用方法(繁瑣)
//class Cat extends Animal{
// @Override
// public void run() {
// System.out.println("貓跑得挺快");
// }
//}
abstract class Animal{
public abstract void run();
}
3、權限修飾符
-
權限由小到大
private → 預設 → protected → public
- 可以修飾成員變量,方法,構造器;不同修飾符修飾的成員能夠被通路的權限也将受到限制
-
四種修飾符的通路權限範圍: private 預設 protected public 本類中 √ √ √ √ 本包下其他類中 X √ √ √ 其他包下的類中 X X X √ 其他包下的子類中 X X √ √
4、Object類常用方法
- Object類是Java中一切類的祖宗類,一個類要麼預設繼承了Object類,要麼間接繼承了Object類
- Object類中的方法是一切類都可以使用的
①public String toString();
- 預設是傳回目前對象在堆記憶體中的位址資訊
- 直接輸出對象可以省略toString()不寫,預設調用
- 直接輸出對象調用toString()方法傳回對象的位址其實是沒有意義的,是以toString()方法存在的意義是為了被子類重寫,以便傳回對象的資料内容輸出
②public boolean equals(Object obj)
- 預設是判斷兩個對象的堆記憶體位址是否一樣,判斷是否是同一個對象,這一點可以直接用==代替equals
- 存在的意義是為了讓子類重寫,便于自定義比較規則
5、Objects類
- jdk1.7才開始有
- Objects類依然是Object的子孫類
-
public static boolean equals(Object a, Object b)
判斷兩個對象是否相等,可以避免空指針異常
-
public static boolean isNull(Object obj)
判斷對象是否為null,如果為null就傳回true