Java 中 this 和 super 的用法詳解

初念初戀發表於2021-07-30

前言

這次我們來回顧一下thissuper這兩個關鍵字的用法,作為一名Java程式設計師,我覺得基礎是最重要的,因為它決定了我們的上限,所以我的文章大部分還是以分享Java基礎知識為主,學好基礎,後面的知識我想學起來就變得簡單。廢話不多說,進入正文。

this

this 關鍵字只能在方法內部使用,表示對呼叫方法的那個物件的引用。

其實簡單來說 this 關鍵字就是表示當前物件,下面我們來具體介紹 this 關鍵字在Java中的用法。

1、呼叫成員變數

在一個類的方法內部,如果我們想呼叫其成員變數,不用 this,我們會怎麼做?

public class ThisTest {

    private String name = "xiaoming";

    public String getName() {
        return name;
    }

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

看上面的程式碼,我們在 ThisTest 類中建立了一個 name 屬性,然後建立了一個 setName 方法,注意這個方法的形參也是 String name,那麼我們通過 name = name 這樣賦值,會改變成員變數 name 的屬性嗎?

public static void main(String[] args) {
    ThisTest thisTest = new ThisTest();
    thisTest.setName("xiaoma");
    System.out.println(thisTest.getName());
}

列印結果是 xiaoming,而不是我們重新設定的 xiaoma,顯然這種方式是不能在方法內部呼叫到成員變數的。因為形參的名字和成員變數的名字相同,setName 方法內部的 name = name,根據最近原則,編譯器預設是將這兩個 name 屬性都解析為形參 name,從而導致我們設值操作和成員變數 name 完全沒有關係,當然設定不了。

解決辦法就是使用 this 關鍵字。我們將 setName 方法修改如下:

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

在呼叫上面的 main 方法進行賦值,列印的結果就是 xiaoma了。

this 表示當前物件,也就是呼叫該方法的物件,物件.name 肯定就是呼叫的成員變數。

2、呼叫構造方法

構造方法是與類同名的一個方法,構造方法沒有返回值,但是也不能用 void 來修飾。在一個類中,必須存在一個構造方法,如果沒有,編譯器會在編譯的時候自動為這個類新增一個無參構造方法。一個類能夠存在多個構造方法,呼叫的時候根據引數來區分。

public class Student {

    private int age;

    private String name;

    public Student() {
        this("小馬",50);
    }

    public Student(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println(name + "今年" + age + "歲了");
    }


    public static void main(String[] args) {
        Student student01 = new Student();
        Student student02 = new Student("小軍",45);
    }
}

通過this("小馬",50)來呼叫另外一個構造方法 Student(String name, int age) 來給成員變數初始化賦值。

輸出結果:

小馬今年50歲了
小軍今年45歲了

Process finished with exit code 0

注意:通過 this 來呼叫構造方法,只能將這條程式碼放在建構函式的第一行,這是編譯器的規定,如下所示:放在第二行會報錯。

image-20210729163733035

3、呼叫普通方法

this 表示當前物件,那麼肯定能夠呼叫當前類的普通方法。

public Student() {
    this.say();
}

public void say(){
    System.out.println("小馬很會唱歌。");
}

4、返回當前物件

public class ThisTest {

    public Object newObject(){
        return this;
    }
}

這表示的意思是誰呼叫 newObject() 方法,那麼就返回誰的引用。

super

Java 中的 super 關鍵字則是表示 父類物件的引用

我們分析這句話父類物件的引用,那說明我們使用的時候只能在子類中使用,既然是物件的引用,那麼我們也可以用來呼叫成員屬性以及成員方法,當然了,這裡的 super 關鍵字還能夠呼叫父類的構造方法。

具體有如下幾種用法

1、呼叫父類的構造方法

Java中的繼承大家都應該瞭解,子類繼承父類,我們是能夠用子類的物件呼叫父類的屬性和方法的,我們知道屬性和方法只能夠通過物件呼叫,那麼我們可以大膽假設一下:在建立子類物件的同時,也建立了父類的物件,而建立物件是通過呼叫建構函式實現的,那麼我們在建立子類物件的時候,應該會呼叫父類的構造方法。

下面我們看這段程式碼:

public class Teacher {

   public Teacher(){
       System.out.println("我是一名人民教師。");
   }
}

class Student extends Teacher {

    public Student(){
        System.out.println("我是一名學生。");
    }
}

下面我們建立子類的物件:

public static void main(String[] args) {
    Student s = new Student();
}

輸出結果:

我是一名人民教師。
我是一名學生。

Process finished with exit code 0

通過列印結果看到我們在建立子類物件的時候,首先呼叫了父類的構造方法,接著呼叫子類的構造方法,也就是說在建立子類物件的時候,首先建立了父類物件,與前面我們猜想的一致。

那麼問題又來了:是在什麼時候呼叫的父類構造方法呢?

可以參考Java官方文件:https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#d5e14278

image-20210729185246748

紅色框內的英文翻譯為:如果宣告的類是原始類Object,那麼預設的建構函式有一個空的主體。否則,預設建構函式只是簡單地呼叫沒有引數的超類建構函式。

也就是說:除了頂級類 Object.class 建構函式沒有呼叫父類的構造方法,其餘的所有類都預設在建構函式中呼叫了父類的建構函式(沒有顯式宣告父類的子類其父類是 Object)。

那麼是通過什麼來呼叫的呢?我們接著看官方文件:

image-20210729185503815

上面的意思大概就是:超類建構函式通過 super 關鍵字呼叫,並且是以 super 關鍵字開頭。

所以上面的 Student類的構造方法實際上應該是這樣的:

class Student extends Teacher {

    public Student(){
        super();//子類通過super呼叫父類的構造方法
        System.out.println("我是一名學生。");
    }


    public static void main(String[] args) {
        Student s = new Student();
    }
}

子類預設是通過 super() 呼叫父類的無參構造方法,如果父類顯示宣告瞭一個有參構造方法,而沒有宣告無參構造方法,例項化子類是會報錯的。

image-20210729185801603

 解決辦法就是通過 super 關鍵字呼叫父類的有參構造方法:

class Student extends Teacher {

    public Student(){
        super("小馬");
        System.out.println("我是一名學生。");
    }


    public static void main(String[] args) {
        Student s = new Student();
    }
}

2、呼叫父類的成員屬性

public class Teacher {

    public String name = "小馬";

    public Teacher() {
        System.out.println("我是一名人民教師。");
    }
}

class Student extends Teacher {

    public Student() {
        System.out.println("我是一名學生。");
    }

    public void fatherName() {
        System.out.println("我的父類名字是:" + super.name);//呼叫父類的屬性
    }

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

輸出結果:

我是一名人民教師。
我是一名學生。
我的父類名字是:小馬

Process finished with exit code 0

3、呼叫父類的方法

public class Teacher {

    public String name;

    public Teacher() {
        System.out.println("我是一名人民教師。");
    }

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

class Student extends Teacher {

    public Student() {
        super();//呼叫父類的構造方法
        System.out.println("我是一名學生。");
    }

    public void fatherName() {
        super.setName("小軍");//呼叫父類普通方法
        System.out.println("我的父類名字是:" + super.name);//呼叫父類的屬性
    }

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

輸出結果:

我是一名人民教師。
我是一名學生。
我的父類名字是:小軍

Process finished with exit code 0

4、this 和 super 出現在同一個構造方法中?

假設 super()this() 關鍵字的前面

首先通過 super() 呼叫父類構造方法,對父類進行一次例項化。接著呼叫 this()this() 方法會呼叫子類的構造方法,在子類的構造方法中又會對父類進行一次例項化。也就是說我們對子類進行一次例項化,對造成對父類進行兩次例項化,所以顯然編譯器是不允許的。

image-20210729191452110

反過來 this()super() 之前也是一樣。而且編譯器有限定 this()super() 這兩個關鍵字都只能出現在構造方法的第一行,將這兩個關鍵字放在一起,總有一個關鍵字在第二行,編譯是不能通過的。

image-20210729191530142

this和super異同

  • super(引數)呼叫基類中的某一個建構函式(應該為建構函式中的第一條語句)。
  • this(引數)呼叫本類中另一種形成的建構函式(應該為建構函式中的第一條語句)。
  • super: 它引用當前物件的直接父類中的成員(用來訪問直接父類中被隱藏的父類中成員資料或函式,基類與派生類中有相同成員定義時如:super.變數名super.成員函式據名(實參)
  • this:它代表當前物件名(在程式中易產生二義性之處,應使用 this 來指明當前物件;如果函式的形參與類中的成員資料同名,這時需用 this 來指明成員變數名)。
  • 呼叫super()必須寫在子類構造方法的第一行,否則編譯不通過。每個子類構造方法的第一條語句,都是隱含地呼叫 super(),如果父類沒有這種形式的建構函式,那麼在編譯的時候就會報錯。
  • super()this() 類似,區別是,super() 從子類中呼叫父類的構造方法,this() 在同一類內呼叫其它方法。
  • super()this() 均需放在構造方法內第一行。
  • 儘管可以用this呼叫一個構造器,但卻不能呼叫兩個。
  • thissuper 不能同時出現在一個建構函式裡面,因為this必然會呼叫其它的建構函式,其它的建構函式必然也會有 super 語句的存在,所以在同一個建構函式裡面有相同的語句,就失去了語句的意義,編譯器也不會通過。
  • this()super() 都指的是物件,所以,均不可以在 static 環境中使用。包括:static 變數,static 方法,static 語句塊
  • 從本質上講,this 是一個指向本物件的指標, 然而 super 是一個 Java 關鍵字。

結尾

我是一個正在被打擊還在努力前進的碼農。如果文章對你有幫助,記得點贊、關注喲,謝謝!

相關文章