1. 程式人生 > >探究Java中的類和繼承--------Java的系列學習之路(15)

探究Java中的類和繼承--------Java的系列學習之路(15)

前言——

今天是軍訓的第5天,昨天打了一天的軍體拳(哈哈哈,好好看本篇博文,不然博主一套軍體拳下去你可能會殘疾  :)

明天是最後一天了,今晚繼續做自己手頭上的事,避免碌碌無為。今天講解的內容——類和繼承,也是跟上一篇一樣,基礎且重要。

第5天沒把這篇文章寫完,今天第六天,早上考了軍體拳,下午考隊列了,趁午休時間趕完這篇文章,晚上可能要去看戲曲表演,不過感覺看戲曲好無聊。。。

歡迎轉載,轉載請註明來處。

Java中的類

a.Java的類檔案

Java中的類是一個.java字尾的class檔案。一個class檔案最多隻允許有一個public類,如果含有public類的話,那麼這個class檔名就必須要和public類的類名一致;如果這個類中沒有public類,都是包訪問許可權的類的話,那麼class檔名可以隨意。如下圖所示:

b.類的載入

當我們要用到某個類,或者不嚴謹地說,當我們new一個類的物件時,如果程式碼中還未曾使用過該類,那麼應該先進行該類的載入,然後再生成物件。類的載入會載入該類中的static變數或者方法,或者static程式碼塊。當類被載入過後,第二次用到該類時就無需再載入了,可以直接生成物件。

如下:

這邊Test4類的main方法中第一次用到Code類,所以要先載入Code類,所以會先載入static成員coderName,然後載入static程式碼塊,這邊會發現"Loading Jian"只打印一次。

執行結果如下:
loading  Jian
I am going to code

c.生成物件時發生了什麼

1.首先Java會對類中每個成員進行一個初始化,如果成員變數在定義時沒有進行顯示地初始化,那麼會被預設初始化。

對於  char、short、byte、int、long、float、double等基本資料型別的變數來說會預設初始化為0(boolean變數預設會被初始化為false);對應引用型別的變數,則會被賦值為null。

這時在Code類當中,coderName這個成員沒有被顯示初始化,由於其是屬於引用型別的變數,所以被預設初始化為null。

2.執行建構函式。如果這個類中沒有自定義建構函式,那麼編譯器會自動生成無參建構函式;如果自定義了建構函式,那麼編譯器就不會自動生成無參建構函式。

會發現,Code類中自定義了Code(String name)的建構函式後,在Test4的main方法中呼叫無參建構函式時會報錯,此時找不到對應的無參建構函式。

二.繼承

在Java中用extends關鍵字表示繼承,而且只允許單繼承。一個子類只能繼承一個父類,但是一個父類卻可以被多個子類繼承。

a.子類繼承父類的哪些東西?

1.肯定能繼承父類的public和protected變數和方法。

2.肯定無法繼承父類的private變數和方法。

3.對於父類的包訪問許可權的變數和方法,如果子類和父類在同一個包下,則子類可以繼承,否則子類不能繼承。

如下:

在這邊Bird類是Pet類的子類,但是二者不在同一個包當中,而父類Pet 中的getType()方法是一個包訪問許可權的方法,很明顯,此時Bird類是沒有繼承這個getType()方法的。

4.對於子類可以繼承的變數和方法,如果子類內部出現了同名的變數或者方法就會發生覆蓋。此時如果在子類中想訪問父類中的變數或者方法的話,應該用super關鍵字。

執行結果:
In Bird
In Pet

b.super關鍵字

有兩種用法。

1.super.父類的成員/父類的方法

2.super(引數), 這個語句放在子類的建構函式中的第一行;除了一定得放在第一行之外,這個語句只能在子類的建構函式中出現一次。

在這邊,父類由於自定義了建構函式,導致了編譯器不會自動新增無參建構函式,父類的建構函式又不能被繼承,所以子類的無參的建構函式必須顯示地新增super(引數)語句,這樣才能呼叫父類的建構函式。如果父類有無參構造器,則在子類的構造器中用super關鍵字呼叫父類構造器不是必須的,因為會自動呼叫無參建構函式。

三.初始化一個子類物件時,發生了啥

這是從其他部落格看到的一個筆試題,感覺特別不錯。

public class Test {
    public static void main(String[] args)  {
        new Circle();
    }
}
 
class Draw {
     
    public Draw(String type) {
        System.out.println(type+" draw constructor");
    }
}
 
class Shape {
    private Draw draw = new Draw("shape");
     
    public Shape(){
        System.out.println("shape constructor");
    }
}
 
class Circle extends Shape {
    private Draw draw = new Draw("circle");
    public Circle() {
        System.out.println("circle constructor");
    }
}

上面這段程式碼的執行結果是啥?
shape draw constructor
shape constructor
circle draw constructor
circle constructor

在這邊,主要考察生成子類物件時建構函式和初始的順序。可以理解為先生成父類部分,再生成子類部分。

父類部分是先初始化父類成員,再呼叫父類的建構函式;

子類部分是先初始化子類成員,再呼叫子類的建構函式。