Java基礎之淺談繼承、多型

漁夫會扎蛙發表於2022-04-03

一、繼承的理解

  • 繼承:簡單通俗的來講,繼承就是一個類繼承另一個類,通常用extends表示繼承。
  • 繼承的類叫子類,被繼承的類叫父類。
  • 子類可以使用父類的變數和方法,同時也可以重寫父類的方法。
  • 在Java中沒有多繼承這一概念,但是有類似多繼承的方法!(通常來講一個父類可以有多個子類,而一個子類只能有一個父類)
//繼承簡單表示
public class Son extends Father{
//將特殊的方法放在子類中
}
class Father {
//我們通常將一般的方法放在父類中,因為父類的方法子類都可以用。
}

二、super、this、instanceof關鍵字

this

  • 上一篇文章已經說過了方法重寫的概念,在這裡就不再重複了。
  • this關鍵字也在上一篇講過,我們可以在構造器中通過this()來呼叫本類的不同引數構造器。通常我們都寫在第一行!
  • 還可以通過this.變數的方式表示使用的是本類的變數

super

  • super關鍵字就是在繼承中應用的,我們可以通過super()呼叫父類的不同引數構造器
  • 同時還可以通過super.方法,呼叫父類的方法。
  • 同時它也是寫在第一行!
  • 通常使用super是因為子類繼承了父類,這樣子類就不必要在寫一些成員變數,直接在構造器中通過super()呼叫父類的構造器,將引數初始化即可。
public class Son extends Father{
    Son(String name, int age) {
        super(name, age);//如果子類的構造器沒有顯示的呼叫父類的構造器,則將預設的呼叫父類的無參構造。
    }
}
class Father {
    String name;
    int age;
    Father(String name,int age) {
        this.name = name;
        this.age = age;
    }
}
//若父類中沒有無參構造,而子類構造器中又沒有呼叫父類的其它構造器,則Java編譯器會報錯。

對於繼承簡言之就是:父類有的子類都有,父類沒有的子類也可以有

instanceof

public void instanceOf(Animal T) {
        if(T instanceof Dog) { //我們傳進來的dog就是此時的T,通過instanceof檢測它是否屬於Dog或者Animal,可以判斷物件的型別。
//此時的語句應該是這樣的 Animal T = new Dog(); 而我們應該將T向下轉型
            t = (Dog) T;
            System.out.println("yes");
        }
    }
        Animal dog = new Dog();
        Animal cat = new Cat();
        cat.instanceOf(dog);//程式將輸出"yes"

三、多型

  • 多型是在繼承的基礎上實現的。也稱之為(向上轉型)
  • 大家只需要記住對於成員變數:編譯看左邊,執行也看左邊。
  • 而對於方法:則是編譯看左邊,執行看右邊。
public class Animal {
    public void play() {
        System.out.println("玩");
    }
    public void eat() {
        System.out.println("吃");
    }
}
public class Cat extends Animal{
    public void eat() {
        System.out.println("貓吃飯,親密度+8");
    }
    public void play() {
        System.out.println("擼貓,體力值-9");
    }
}
public class Test {
    public static void main(String[] args) {
        Animal cat = new Cat();//此時cat被看成是Animal的物件,但實際上本質是Cat的。
//在編譯階段我們看左邊,它是Animal騙過編譯器,但真正執行的時候它會看右邊。
        cat.eat();
        cat.play();
//最終輸出“貓吃飯,親密度+8”和“擼貓,體力值-9”。這就是多型的應用
//看右邊,就是先去尋找Cat中是否有重寫的父類方法,如果有則呼叫自己的。如果沒有則用父類的。
//可以記為:先調子類,再調父類。
    }
}

Animal cat = new Cat();這也是向上轉型,將Cat類的轉成了Animal

3.1abstract

  • 抽象類:使用abstract關鍵字
  • 抽象類中的方法不需要實現,只需要宣告佔一個位置就行。我們可以在子類中去具體實現這個方法。
  • 這樣更有靈活性,就像我們定義了一個抽象方法eat(),而不同的子類可以去實現成不同的方法,貓可以實現吃魚,狗可以實現吃翔,使程式更加簡單化。
  • 抽象類無法例項化,也就不能造物件了。

3.2許可權修飾

  1. 再次總結許可權修飾範圍
  2. 僅對本類可見————private
  3. 對外部完全可見————public
  4. 對本包和所有子類可見————protected
  5. 對本包可見————預設,也就使預設的

四、Objcet

  • Object是所有類的父類
  • 既是沒有明顯寫出繼承Object,但也預設認為Object是父類

4.1equals方法

  • Object類中的equals()方法比較的是記憶體地址,通常我們都會重寫equals()方法,達到值比較的目的。
  • getClass方法將返回一個物件所屬的類。我們可以通過它檢測兩個物件是否屬於同一個類。

Java規範要求equals方法具有下面的特性:
1.自反性:對於任何非空引用x,x.equals(x)應該返回true。
2.對稱性:對於任何引用x和y,當且僅當y.equals(x)返回true時,x.equals(y)返回true。
3.傳遞性:對於任何引用x、y和z,如果x.equals(y)返回true,y.equals(z)返回true,則x.equals(z)也應該為true。
4.一致性:如果x和y引用的物件沒有發生變化,反覆呼叫x.equals(y)應該返回同樣的結果。
5.對於任意非空引用x,x.equals(null)應該返回false。

  • 但是對於一個e是Employee物件,m是Manager物件,並且兩個物件的值都是相同的。如果呼叫e.equals(m)則返回true。若反過來呼叫m.equals(e)則返回false。這就違反了我們的對稱性。
  • 因為我們用的是instanceof檢測的,但是父類instanceof子類是無法進行的。所以這也是instanceof的缺點
  • 我們可以通過getClass來比較兩個物件是否屬於同一個類,但是這樣也有限制,就是多型的情況下返回false。

4.2hashCode方法

  • String類計算雜湊碼演算法:
點選檢視程式碼
int hash = 0;
    for(int i = 0; i < length(); i++) {
      hash = 31*hash + charAt(i);
  }
- 對於字串的雜湊碼,是看字串的內容而定的。意味著兩個字串內容相同,則他們的雜湊碼也相同。

4.3toString方法

  • 其實這個方法非常簡單,就是把我們的欄位以字串的形式,好看的輸出出來。
@Override
    public String toString() {
        return getClass().getName()
                +"{" 
                + "tili=" 
                + tili 
                + ", qimi=" 
                + qimi 
                + '}';
    }
  • 在使用的時候我們可以寫成
  • System.out.println(x.toString());
  • System.out.println(x);這樣會預設呼叫toString()方法,可以簡略不寫

但是在有時候我們用toString方法是會出現輸出java.io.PrintStream@2f6684和[I@1a46e30的情況

1.這是因為Objcet類定義了toString方法,可以列印物件的類名和雜湊碼,所以需要我們對toString方法進行重寫
2.陣列也繼承了Objcet類的toString,如果我們使用時不重寫toString,則會出現[I@1a46e30,補救辦法就時使用Arrays.toString()
3.若是二維陣列,則可以使用Arrays.deepToString()方法
4.強烈建議在每一個類中都重寫toString方法。

五、泛型陣列列表

  • 在做題時,必須確定陣列的長度以後才能夠使用,這樣使我們非常的不方便!
  • 所以我們就可以使用一個動態擴容的陣列,這樣就不必定義它的初始化長度。
  • ArraysList list = new ArrayList<>(100) 這是初始化100的陣列,可動態擴容
  • 如果說空間過多浪費了,可以使用trimToSize()方法,將沒用過的空間釋放掉。
  • 具體詳細的ArrayList用法,我們在日後的集合學習。

5.1將字串轉成整型

int x = Integer.parseInt(s);

5.2將數字轉成字串

String s = String.ValueOf(x);

5.3可變引數

System.out.println(sum(1,2,3,4,5));
    public static int sum(int... a) {
        int total = 0;
        for(int i:a) {
            total += i;
        }
        return total;
    }

六、列舉類

  • 列舉用enum表示
  • public enum Size{1,2,3,4,5};一次自增1
  • 列舉的構造器總是私有的

七、結尾

  • 對於繼承、多型內容就總結這麼多,希望大家可以多多練習。如果有不足之處,希望大家多多包涵,多多支援。如果有不懂的地方可以直接私信問我,歡迎來訪!
  • 我將會繼續更新關於Java的學習知識,感興趣的小夥伴可以關注一下。
  • 文章寫得比較走心,用了很長時間,絕對不是copy過來的!
  • 尊重每一位學習知識的人,同時也尊重每一位分享知識的人。

相關文章