Java語言的特性及上轉型對象

一. Java語言的特性

封裝:封裝是指屬性私有化,根據需要提供setter和getter方法來訪問屬性。即隱藏具體屬性和實現細節,僅對外開放接口,控制程序中屬性的訪問級別。封裝的目的是增強安全性和簡化編程,使用者不必在意具體實現細節,而只是通過外部接口(此處的接口可以理解爲某些訪問私有屬性的方法如JavaBean中的屬性以及對應的getter和setter方法)即可訪問類的成員。此時如果類中有一個帶參的構造函數,那一定要寫一個不帶參的構造函數,以方便通過無參的構造函數實例化的對象使用成員方法。

繼承:繼承是指多個相同的屬性和方法提取出來,新建一個父類。Java中一個類只能繼承一個父類即子類和父類的關係是“is-a”關係,而一個父類可以被多個子類繼承,而且子類不能繼承父類中訪問權限爲private的成員變量和方法。子類可以重寫父類中的方法,及命名與父類同名的成員變量,而且子類可以添加新的方法和屬性。另外,子類不能繼承父類的構造方法,但是子類可以通過super()來調用父類的構造方法。從而實現了代碼的複用,但是應該儘量減少繼承關係以降低代碼的耦合度。

繼承涉及內容:構造器,protected關鍵字,向上轉型。

構造器:繼承父類的屬性和方法,除了那些private的外還有一樣是子類繼承不了的—構造器。對於構造器而言,它只能夠被調用,而不能被繼承。 調用父類的構造方法我們使用super()即可。對於子類而已,其構造器的正確初始化是非常重要的,而且當且僅當只有一個方法可以保證這點:在構造器中調用父類構造器來完成初始化,而父類構造器具有執行父類初始化所需要的所有知識和能力。

public class Person {
    protected String name;
    protected int age;
    protected String sex;
    
    Person(){
        System.out.println("Person Constrctor...");
    }
}

public class Husband extends Person{
    private Wife wife;

    Husband(){
        System.out.println("Husband Constructor...");
    }
    
    public static void main(String[] args) {
        Husband husband  = new Husband();
    }
}

Output:
Person Constrctor...
Husband Constructor...

通過這個示例可以看出,構建過程是從父類“向外”擴散的,也就是從父類開始向子類一級一級地完成構建。而且我們並沒有顯示的引用父類的構造器,但編譯器會默認給子類調用父類的構造器。而且這個默認調用父類的構造器是有前提的:父類有默認構造器。如果父類沒有默認構造器,我們就要必須顯示的使用super()來調用父類構造器,否則編譯器會報錯:無法找到符合父類形式的構造器。

public class Person {
    protected String name;
    protected int age;
    protected String sex;
    
    Person(String name){
        System.out.println("Person Constrctor-----" + name);
    }
}

public class Husband extends Person{
    private Wife wife;

    Husband(){
        super("chenssy");
        System.out.println("Husband Constructor...");
    }
    
    public static void main(String[] args) {
        Husband husband  = new Husband();
    }
}

Output:
Person Constrctor-----chenssy
Husband Constructor...

所以綜上所述:對於繼承而已,子類會默認調用父類的構造器,但是如果沒有默認的父類構造器,子類必須要顯示的指定父類的構造器,而且必須是在子類構造器中做的第一件事(第一行代碼)。

對象的上轉型對象:存在老虎類Tiger和動物類Animal,當我們說老虎是動物時,老虎就是去了它獨有的屬性和功能,只是具有動物的特性。 由此可以引申到Java語言的上轉型對象。

Animal a = new Tiger();
或者
Tiger b = new Tiger();
Animal a = b;

如代碼所示:我們成對象a是對象b的上轉型對象(好比說“老虎是動物”)

上轉型對象的特點:1. 上轉型對象不能使用子類新增的成員變量和新增的方法。

                                 2. 上轉型對象可以操作子類繼承或者隱藏的成員變量,也可以使用子類繼承或者重寫的方法。即上轉型對象可以可以操縱父類原有的屬性和功能,無論這些方法是否被重寫。其作用等價於子類對象調用這些方法。因此,如果子類重寫父類的方法後,當對象的上轉型對象調用這個實例化方法時一定是調用了子類重寫的實例方法,如圖所示:

                                 

我們可以將圖中的對象理解爲Tiger的實例化對象b,對象的上轉型對象可以理解爲Animal的實例化對象a。

注:1. 可以將對象的上轉型對象在強制轉換爲一個子類對象,這時候該子類對象又具備了子類所有的屬性和功能,

       即: Father father = new Son();//father是Son實例化對象的上轉型對象。

               Son son = (Son) father; //把上轉型對象強制轉換成子類的對象。

       2. 不能將父類創建的對象的引用賦值給子類聲明的對象(即不能說“人是美國人”)。

protected關鍵字:private訪問修飾符,對於封裝而言,是最好的選擇,但這個只是基於理想的世界,有時候我們需要這樣的需求:我們需要將某些事物儘可能地對這個世界隱藏,但是仍然允許子類的成員來訪問它們。這個時候就需要使用到protected。對於protected而言,它指明就類用戶而言,他是private,但是對於任何繼承與此類的子類而言或者其他任何位於同一個包的類而言,他卻是可以訪問的。

public class Person {
    private String name;
    private int age;
    private String sex;

    protected String getName() {
        return name;
    }

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

    public String toString(){
        return "this name is " + name;
    }
    
    /** 省略其他setter、getter方法 **/
}

public class Husband extends Person{
    private Wife wife;

    public  String toString(){
        setName("chenssy");    //調用父類的setName();
        return  super.toString();    //調用父類的toString()方法
    }

    public static void main(String[] args) {
        Husband husband = new Husband();
        
        System.out.println(husband.toString());
    }
}

Output:
this name is chenssy

多態:多態可以分爲設計時多態和運行時多態。簡單來說,多態就是同一事務,由於條件不同,產生的結果不同。而使用多態的原則是在聲明變量或者是方法的參數列表時能用父類用父類,能用接口用接口。

設計時多態:即重載,是指Java允許方法名相同而參數不同(參數個數或者參數類型不同,返回值可以相同也可以不同)。

運行時多態:即重寫,是指Java運行時根據調用方法的實際功能來決定調用哪個方法。從而實現了代碼的靈活度,同時在使用多態時,優先調用子類的方法,如果子類沒有重寫父類的方法,則調用父類的方法。

多態的必要條件:繼承,重寫,向上轉型(父類引用指向子類的實例化對象)

多態的使用過程:a. 定義子類extends父類,或者實現某接口,並重寫父類中的方法;

                             b. 聲明父類類型的實例化變量將其賦予子類類型的實例對象,即 Son son = new Father();

                             c. 調用相應的方法。使用多態時,父類在在調用方法時,優先調用子類的方法。如果子類沒有重寫父類的方法,則再調用父類的方法。

public class Wine {
    public void fun1(){
        System.out.println("Wine 的Fun.....");
        fun2();
    }
    
    public void fun2(){
        System.out.println("Wine 的Fun2...");
    }
}

public class JNC extends Wine{
    /**
     * @desc 子類重載父類方法,父類中不存在該方法,向上轉型後,父類是不能引用該方法的
     * @param a
     * @return void
     */
    public void fun1(String a){
        System.out.println("JNC 的 Fun1...");
        fun2();
    }
    
    /**
     * 子類重寫父類方法
     * 指向子類的父類引用調用fun2時,必定是調用該方法
     */
    public void fun2(){
        System.out.println("JNC 的Fun2...");
    }
}

public class Test {
    public static void main(String[] args) {
        Wine a = new JNC(); 
        a.fun1();
    }
}

Output:
Wine 的Fun.....
JNC 的Fun2...

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章