面向對象的三大特性

三大特性

封裝

一句話:屬性私有化,get/setjava

在面向對象程式設計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實現細節部分包裝、隱藏起來的方法。編程

封裝能夠被認爲是一個保護屏障,防止該類的代碼和數據被外部類定義的代碼隨機訪問。安全

要訪問該類的代碼和數據,必須經過嚴格的接口控制。ide

封裝最主要的功能在於咱們能修改本身的實現代碼,而不用修改那些調用咱們代碼的程序片斷。學習

適當的封裝可讓程式碼更容易理解與維護,也增強了程式碼的安全性。測試

優勢

  1. 提升程序的安全性,保護數據。
  2. 隱藏信息,實現細節。
  3. 統一接口
  4. 減小耦合。

實現封裝

  1. 修改屬性的可見性來限制對屬性的訪問(通常限制爲private), 只能本類才能訪問,其餘類都訪問不了,如此就對信息進行了隱藏。
  2. 對每一個值屬性提供對外的公共方法訪問,也就是建立一對賦取值方法,用於對私有屬性的訪問
public class Student {
    private int age;// 年齡
    private String name;// 名字
    
    // 提供一些public 的get、set方法。

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        if (age > 100 || age < 0) {
            this.age = 3;
        } else {
            this.age = age;
        }
    }
}

採用 this 關鍵字是爲了解決實例變量(private String name)和局部變量(setName(String name)中的name變量)之間發生的同名的衝突。this

public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        //student.name; // private私有化以後,外部類沒法訪問該屬性。
        student.setName("小明");
        student.setAge(18); // 年齡在內部處理邏輯
        // student.setAge(999);  //處理不合理的年齡
        String name = student.getName();
        int age = student.getAge();
        System.out.println(name + age +"歲啦");
    }
}

以上實例中public方法是外部類訪問該類成員變量的入口。設計

一般狀況下,這些方法被稱爲getter和setter方法。code

所以,任何要訪問類中私有成員變量的類都要經過這些getter和setter方法。對象

繼承

一句話:子類繼承父類的特徵和行爲。

extends 是"擴展"的意思,子類是父類的擴展。

繼承是java面向對象編程技術的一塊基石,由於它容許建立分等級層次的類。

繼承就是子類繼承父類的特徵和行爲,使得子類對象(實例)具備父類的實例域和方法,或子類從父類繼承方法,使得子類具備父類相同的行爲。

特性

  • 子類擁有父類非 private 的屬性、方法。
  • 子類能夠擁有本身的屬性和方法,即子類能夠對父類進行擴展。
  • 子類能夠用本身的方式實現父類的方法。(重寫)
  • Java 的繼承是單繼承,可是能夠多重繼承,單繼承就是一個子類只能繼承一個父類,多重繼承就是,例如 A 類繼承 B 類,B 類繼承 C 類,因此按照關係就是 C 類是 B 類的父類,B 類是 A 類的父類,這是 Java 繼承區別於 C++ 繼承的一個特性。
  • 提升了類之間的耦合性(繼承的缺點,耦合度高就會形成代碼之間的聯繫越緊密,代碼獨立性越差)。

關鍵字

繼承可使用 extends 和 implements 這兩個關鍵字來實現繼承,並且全部的類都是繼承於 java.lang.Object,

當一個類沒有繼承的兩個關鍵字,則默認繼承object祖先類(這個類在 java.lang 包中,因此不須要 import)。

extends:在 Java 中,類的繼承是單一繼承,也就是說,一個子類只能擁有一個父類,因此 extends 只能繼承一個類。

implements:能夠同時繼承多個接口(接口跟接口之間採用逗號分隔),使java具備多繼承的特性。

public interface A {
    public void eat();
    public void sleep();
}
 
public interface B {
    public void show();
}
 
public class C implements A,B {
}

super:咱們能夠經過super關鍵字來實現對父類成員的訪問,用來引用當前對象的父類。

this:指向本身的引用。

final :聲明類能夠把類定義爲不能繼承的,即最終類;或者用於修飾方法,該方法不能被子類重寫:

區別 前提 構造方法
this 表示自己調用者這個對象 沒有繼承也可使用 this()
super 表明父類對象的引用 只能在繼承條件纔可使用 super()

注意點

  • super()調用父類的構造方法,必須在構造方法的第一個
  • this()調用本身的構造方法,必須在構造方法的第一個,因此this() super() 不能同時出現
  • super()只能出如今子類的方法或構造方法中!

繼承格式

class 父類 {
}
 
class 子類 extends 父類 {
}

父類Person

/**
 * 隱式繼承Object類
 */
public class Person {
    private String name;
    public void say() {
        System.out.println("說話說話");
    }
}

子類Student繼承Person

public class Student extends Person {

}
public class Application {
    public static void main(String[] args) {
        Student student = new Student();
        student.say();
    }
}

子類繼承了父類的公共方法和屬性

繼承類型

繼承是類和類之間的一種關係。除此以外,類和類之間的關係還有依賴、組合、聚合等

img

IDEA快捷鍵 ctrl + H 查看繼承關係

方法重寫

重寫都是方法的重寫,與屬性無關

image-20200510214544325

重寫:須要有繼承關係,子類重寫父類的非靜態方法!

  1. 方法名必須相同
  2. 參數列表必須相同
  3. 修飾符能夠擴大但不能縮小 public >protected>default>private
  4. 拋出的異常範圍:能夠被縮小但不能擴大;

爲何須要重寫?父類的功能,子類不必定須要,或者不必定知足。

多態

一句話:同一個方法能夠根據發送對象的不一樣而採起多種不一樣的行爲方式。

使用手機掃描二維碼支付時,二維碼並不知道客戶是經過何種方式進行支付,只有經過二維碼後才能判斷是走哪一種支付方式執行對應流程。

img

多態能夠實現動態編譯:類型在執行過程當中才能夠肯定:加強可擴展性~

多態是同一個行爲具備多個不一樣表現形式或形態的能力。

多態就是同一個接口,使用不一樣的實例而執行不一樣操做。

前提條件

  1. 繼承
  2. 重寫
  3. 父類引用指向子類

特徵

  • 對象能執行的方法和左邊的類型有關,和右邊的關係不大
  • 子類能調用的方法都是本身的或者繼承父類的。
  • 父類型能夠指向子類,可是不能調用子類獨有的方法。
  • 父類想要執行子類的方法須要向下轉型,高轉低是強制轉換!

優勢

  1. 減耦合
  2. 加強能夠替換性
  3. 可擴展性
  4. 靈活性等

關鍵詞instanceof

instanceof:測試它左邊的對象是不是它右邊的類的實例

判斷一個對象是什麼類型,instanceof能夠判斷兩個類之間是否存在父子關係

image-20200512092823693

public class Application {
    public static void main(String[] args) {
        // instanceof
        // 1.先判斷左側的引用類型與右邊類是否有關係
        // 2.再判斷左側的實際類型與右邊類是否有關係

        // 繼承關係
        //      Object
        //      /   \
        //  String  Person
        //          /   \
        //     Student   Teacher

        // 公式 ClassA obj = new ClassB();
        // obj instanceof 任意類
        // 可以經過編譯 取決於ClassA 與 任意類 有沒有關係
        // true/false 取決於ClassB 與 任意類 有沒有關係


        // 對象的引用類型是Student類
        Student obj1 = new Student();
        System.out.println("=======Student->Student==========");
        System.out.println(obj1 instanceof Student);
        System.out.println(obj1 instanceof Person);
        System.out.println(obj1 instanceof Object);
        // System.out.println(obj1 instanceof Teacher); // Student 和 Teacher 是兄弟關係,報錯~
        // System.out.println(obj1 instanceof String); // Student 與 String無直接聯繫,報錯!


        Person obj2 = new Student();
        System.out.println("=======Person->Student==========");
        System.out.println(obj2 instanceof Student);
        System.out.println(obj2 instanceof Person);
        System.out.println(obj2 instanceof Object);
        System.out.println(obj2 instanceof Teacher);
        // obj2 指向的是Student類,與Teacher無直接聯繫
        //System.out.println(obj2 instanceof String); // Person 與 String無直接聯繫,報錯!

        Object obj3 = new Student();
        System.out.println("=======Object->Student==========");
        System.out.println(obj3 instanceof Student);
        System.out.println(obj3 instanceof Person);
        System.out.println(obj3 instanceof Object);
        System.out.println(obj3 instanceof Teacher);
        System.out.println(obj3 instanceof String);

        Person obj4 = new Person();
        System.out.println("=======Person->Person==========");
        //
        System.out.println(obj4 instanceof Student);
        System.out.println(obj4 instanceof Person);
        System.out.println(obj4 instanceof Object);
        System.out.println(obj4 instanceof Teacher);
        // System.out.println(obj4 instanceof String);
        // Person 與 String無直接聯繫,報錯!
    }
}

類型轉換

基礎類型轉換

  • 低 ------>高 隱式轉換
  • 高------->低 強制轉換

引用類型轉換

  • 低(子類)----->高(父類)

  • 低轉高:Person obj1 = new Student(); 即向上轉換,不須要強制轉換

  • 高轉低 Student obj2 = (Student)obj1; 即向下轉換,須要強制轉換

注意:以前學習繼承的時候說,子類是父類的擴展,因此子類轉換成父類時會丟失一些自己的方法或屬性。

父類型能夠指向子類,可是不能調用子類獨有的方法。由於子類獨有的方法丟失了,沒法調用。

多態小結

  • 多態是方法的多態,屬性沒有多態

  • 父類和子類

    • 有聯繫。instanceof
    • 類型轉換異常!ClassCastException!
    • 子類轉換成父類,向上轉型,丟失方法
    • 父類轉換成子類,向下轉型 (強制轉換)
  • 存在條件

    • 繼承關係
    • 方法須要重寫
    • 父類引用指向子類對象!
  • 不能重寫的方法

    • static 靜態方法屬於類,不屬於實例
    • final常量修飾不能繼承
    • private 方法私有

OOP面向對象的編程思想就是抽象

[代碼區](# 多態代碼)

多態的表現

多態代碼

第一種狀況 對象的實際類型肯定,指向的引用類型不肯定(能夠用父類引用類型指向子類對象)

以下有Person類

Person.java

public class Person {
    public void say() {
        System.out.println("father---say");
    }
}

Student.java

// 繼承 Person 類
public class Student extends Person {
}

有繼承關係才能夠指向

Application.java

/**
 * 測試多態的表現
 */
public class Application {
    public static void main(String[] args) {
        // 一個對象的實際類型是肯定的
        // new Student(); // 建立出一個學生
        // new Person();  // 建立出一我的

        // 能夠指向的引用類型就不肯定了
        Student s1 = new Student(); // new 一個學生 名字叫 學生
        Person s2 = new Student();// new 一個學生 名字叫 人(學生也是人,他繼承了人)
        Object s3 = new Student();
        s2.say();
    }
}

運行結果

father---say

子類能調用的方法都是本身的或者繼承父類的。若是子類中沒有say方法,則調用繼承於父類的say方法。

若是在子類重寫了父類的say方法,則調用自己的say方法。以下代碼重寫了父類的say方法:

Student.java

public class Student extends Person {
    @Override
    public void say() { // 重寫父類say方法
        System.out.println("son ---- say");
    }
}

Application.java

/**
 * 測試多態的表現
 */
public class Application {
    public static void main(String[] args) {
        // 一個對象的實際類型是肯定的
        // new Student(); // 建立出一個學生
        // new Person();  // 建立出一我的

        // 能夠指向的引用類型就不肯定了
        Student s1 = new Student(); // new 一個學生 由 學生
        Person s2 = new Student();// new 一個學生 由人接收(學生也是人,他繼承了人)
        Object s3 = new Student();
        s1.say();// 學生 說
        s2.say();// 學生 說
        
    }
}

運行結果

son ---- say
son ---- say

由於實例是肯定的,s1,s2都是new 出來的Student()實例對象,方法的功能與實例的實現有關。

若是在Student類中添加一個eat()方法

public class Student extends Person {
    @Override
    public void say() {
        System.out.println("son ---- say");
    }
    
    public void eat() {
        System.out.println("son ---- eat");
    }
}
public class Application {
    public static void main(String[] args) {

        Student s1 = new Student();
        Person s2 = new Student();

        //對象能執行的方法和左邊的類型有關,和右邊的關係不大
        s1.say();// 學生 說
        s2.say();// 學生 說

        s1.eat(); // s1 左邊是學生類,學生類裏面有say方法。成功調用
        //s2.eat(); // s2 左邊是人類,人類中沒有eat方法,又不能繼承,因此調用失敗
    }
}

對象能執行的方法和左邊的類型有關,涉及到類型轉換,高-->低 會丟失精度。好比

public class Test {
    public static void main(String[] args) {
        float a = 1.5f;
        long b = 99999999999999L;
        System.out.println((int)a); // 結果打印1 丟失了小數部分
        System.out.println((int)b); // 結果打印276447231  丟失數據溢出部分
    }
}

但在學習繼承的時候知道,子類繼承父類獲取父類的非私有屬性和方法,子類是父類的擴展。

這裏引用類型和基本類型的轉換是存在區別的,基本類型高精度轉型爲低精度會丟失數據。而引用類型子類轉型爲父類會丟失方法或屬性。

相關文章
相關標籤/搜索