前言
這次我們來回顧一下this
和super
這兩個關鍵字的用法,作為一名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 來調用構造方法,只能將這條代碼放在構造函數的第一行,這是編譯器的規定,如下所示:放在第二行會報錯。
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
紅色框內的英文翻譯為:如果聲明的類是原始類Object,那么默認的構造函數有一個空的主體。否則,默認構造函數只是簡單地調用沒有參數的超類構造函數。
也就是說:除了頂級類 Object.class 構造函數沒有調用父類的構造方法,其余的所有類都默認在構造函數中調用了父類的構造函數(沒有顯式聲明父類的子類其父類是 Object)。
那么是通過什么來調用的呢?我們接着看官方文檔:
上面的意思大概就是:超類構造函數通過 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() 調用父類的無參構造方法,如果父類顯示聲明了一個有參構造方法,而沒有聲明無參構造方法,實例化子類是會報錯的。
解決辦法就是通過 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()
方法會調用子類的構造方法,在子類的構造方法中又會對父類進行一次實例化。也就是說我們對子類進行一次實例化,對造成對父類進行兩次實例化,所以顯然編譯器是不允許的。
反過來 this()
在 super()
之前也是一樣。而且編譯器有限定 this()
和 super()
這兩個關鍵字都只能出現在構造方法的第一行,將這兩個關鍵字放在一起,總有一個關鍵字在第二行,編譯是不能通過的。
this和super異同
super(參數)
:調用基類中的某一個構造函數(應該為構造函數中的第一條語句)。this(參數)
:調用本類中另一種形成的構造函數(應該為構造函數中的第一條語句)。super
: 它引用當前對象的直接父類中的成員(用來訪問直接父類中被隱藏的父類中成員數據或函數,基類與派生類中有相同成員定義時如:super.變量名
、super.成員函數據名(實參)
。this
:它代表當前對象名(在程序中易產生二義性之處,應使用 this 來指明當前對象;如果函數的形參與類中的成員數據同名,這時需用 this 來指明成員變量名)。- 調用
super()
必須寫在子類構造方法的第一行,否則編譯不通過。每個子類構造方法的第一條語句,都是隱含地調用super()
,如果父類沒有這種形式的構造函數,那么在編譯的時候就會報錯。 super()
和this()
類似,區別是,super()
從子類中調用父類的構造方法,this()
在同一類內調用其它方法。super()
和this()
均需放在構造方法內第一行。- 盡管可以用
this
調用一個構造器,但卻不能調用兩個。 this
和super
不能同時出現在一個構造函數里面,因為this
必然會調用其它的構造函數,其它的構造函數必然也會有super
語句的存在,所以在同一個構造函數里面有相同的語句,就失去了語句的意義,編譯器也不會通過。this()
和super()
都指的是對象,所以,均不可以在static
環境中使用。包括:static
變量,static
方法,static 語句塊
。- 從本質上講,
this
是一個指向本對象的指針, 然而super
是一個 Java 關鍵字。
結尾
我是一個正在被打擊還在努力前進的碼農。如果文章對你有幫助,記得點贊、關注喲,謝謝!