面試:對封裝、繼承、多型的理解。
1.封裝
封裝:就是隱藏物件的屬性和實現細節,僅對外提供公共訪問方式。
封裝的好處:隱藏類的實現細節;讓使用者只能通過程式設計師規定的方法來訪問資料;可以方便的加入存取控制語句,限制不合理操作.
封裝時的許可權控制符區別如下:
1 /* 2 * 封裝演示 3 */ 4 public class Dog { 5 // 私有化屬性 6 private String name; 7 private String sex; 8 private String color; 9 10 // 封裝欄位 11 public String getName() {12 return name; 13 } 14 15 public void setName(String name) { 16 this.name = name; 17 } 18 19 public String getSex() { 20 return sex; 21 } 22 23 public void setSex(String sex) { 24 this.sex = sex; 25 } 26 27 public String getColor() {28 return color; 29 } 30 31 public void setColor(String color) { 32 this.color = color; 33 } 34 35 }
Penguin類同理。
2.繼承
語法:
修飾符SubClass extends SuperClass{
//類定義部分
}
在java中,繼承通過extends關鍵字來實現,其中SubClass稱為子類,SuperClass稱為父類。修飾符如果是public,該類在整個專案中可見;不寫public修飾符則該類只在當前包可用;不可以使用private和protected修飾符.
繼承:是 java 中實現程式碼重用的重要手段之一.java中只支援單繼承,即每個類只能有一個父類.繼承表達的是 is a 的關係,或者說是一種特殊和一般的關係.
在java中,所有的java類都直接或間的接的繼承了java.lang.long.Object類.Object類是所有java類的祖先.在定義一個類時,沒有使用 extends 關鍵字,那麼這個類直接繼承Object類.
在java中,子類可以從父類中繼承的有:
繼承 public 和 protected 修飾的屬性和方法,不管子類和父類是否在同一個包裡.
繼承預設許可權修飾符修飾的屬性和方法,但子類和父類必須在同一個包裡.
子類無法繼承父類的有:
無法繼承 private 修飾的屬性和方法
無法繼承父類的構造方法
如果從父類繼承的方法不能滿足子類的需求,在子類中可以對父類的同名方法進行重寫 ,以符合要求.
抽象出Dog類和Penguin類和父類Pet類(Pet類為抽象類,不能被例項化)
/** * Dog和Penguin的父類Pet,而Pet物件是沒有意義的,只是抽象出來的一個概念, 因此給Pet類添* * 加abstract修飾符,讓其成為一個抽象類,抽象不能被例項化. * */ public abstract class Pet { // 私有化屬性 private String name; private String sex; // 封裝欄位 public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } // 無參構造方法 public Pet() { } /** * 有參構造方法 * * @param name * 名稱 * @param sex * 性別 * */ public Pet(String name, String sex) { this.setName(name); this.setSex(sex); } // Pet類的抽象方法eat(),抽象方法必需被子類重寫 public abstract void eat(); // final修飾的方法不能被子類重寫 public final void println() { // 方法體… } } // 狗繼承動物類 class Dog extends Pet { private String color; // 封裝欄位 public String getColor() { return color; } public void setColor(String color) { this.color = color; } // 無參構造方法 public Dog() { } // 有參構造方法 public Dog(String name, String sex, String color) { // 傳參到父類的構造方法,此處不能用this.name = name..... super(name, sex); // 呼叫setColor()方法給屬性color賦值 this.setColor(color); } // 重寫父類eat()方法 public void eat() { // 方法體.... } } // 企鵝繼承動物類 class Penguin extends Pet { private double weight; public double getWeight() { return weight; } public void setWeight(double weight) { this.weight = weight; } // 重寫父類eat()方法 public void eat() { // 方法體…. } } // 測試類Test class Test { public static void main(String[] args) { String name = "dog1"; String sex = "男"; String color = "red"; // 例項化物件 Dog dog = new Dog(); dog.setName(name); // 通過從父類處繼承來的方法設定dog的屬性name dog.setSex(sex); // 通過有參建構函式例項化物件 Dog dog1 = new Dog("dogName", "man", "black"); // 呼叫eat()方法,此方法被重寫了 dog1.eat(); } }
繼承條件下構造方法呼叫規則如下
如果子類的構造方法中沒有通過super顯示呼叫父類的有參構造方法,也沒有通過this顯示呼叫自身的其他構造方法,則系統會預設先呼叫父類的無參構造 方法.在這種情況下寫不寫super()語句效果都是一樣.
如果子類的構造方法中通過super顯示呼叫父類的有參構造方法,那將執行父類相應構造方法,而不執行父類無參構造方法.
如果子類的構造方法中通過this顯示呼叫自身的其他構造方法,在相應 構造方法中應用以上兩條規則.
特別注意的是,如果存在多級繼承關係,在建立一個子類物件時,以上規則會多次向更高一級父類應用,一直到執行頂級父類Object類的無參構造方法為止.
abstract和final是功能相反的兩個關鍵字,abstract可以用來修飾類和方法,不能用來修飾屬性和構造方法.final可以用來修飾類,方法和屬性,不能修飾構造方法.
3.多型
多型的三個條件:
1. 繼承的存在(繼承是多型的基礎,沒有繼承就沒有多型).
2. 子類重寫父類的方法(多型下呼叫子類重寫的方法).
3. 父類引用變數指向子類物件(子類到父類的型別轉換).
子類轉換成父類時的規則:
將一個父類的引用指向一個子類的物件,稱為向上轉型(upcastiog),自動進行型別轉換.
此時通過父類引用呼叫的方法是子類覆蓋或繼承父類的方法,不是父類的方法.
此時通過父類引用變數無法呼叫子類特有的方法.
如果父類要呼叫子類的特有方法就得將一個指向子類物件的父類引用賦給一個子類的引用,稱為向下轉型,此時必須進行強制型別轉換.
public class Person // 人類 { String name; int age; public void eat() { System.out.println("人們在吃飯!"); } } class Chinese extends Person { // 重寫父類方法 public void eat() { System.out.println("中國人在吃飯!"); } // 子類特有方法,當父類引用指向子類物件時無法呼叫該方法 public void shadowBoxing() { System.out.println("練習太極拳!"); } } class English extends Person { // 重寫父類方法 public void eat() { System.out.println("英國人在吃飯!"); } } // 測試類 class TestEat { public static void main(String[] args) { TestEat test = new TestEat(); // 引用指向中國人,建立中國人類物件 Person person1 = new Chinese(); // 此時呼叫的是Chinese的eat()方法 test.showEat(person1); Person person2 = new English(); // 此時呼叫的是English的eat()方法 test.showEat(person2); // 強制型別轉換(向下轉型) Chinese chinese = (Chinese) person1; // 向下轉型後,呼叫子類的特有方法 chinese.shadowBoxing(); } // 使用父類作為方法的形參,實現多型 public void showEat(Person person) { // 傳入的是哪具物件就呼叫哪個物件的eat()方法 person.eat(); } }