this關鍵字與super關鍵字詳解
一.this關鍵字
1.例項一:
(1)需求:使用Java類描述一個動物;
(2)例項:
class Animal{ String name; //成員變數 String color; public Animal(String n,String c){ name = n; color = c; } public void eat(){ String name = "老鼠"; //區域性變數 System.out.println(name+"在吃……"); } } class Demo1{ public static void main(String[] args){ Animal dog = new Animal("狗","白色");//此時在記憶體中存在兩份name資料 Animal cat = new Animal("貓","黑色"); cat.eat(); } }
(3)執行結果:
(4)存在的問題:
當我們new一個動物cat時,讓cat去呼叫eat方法,結果顯示的卻是老鼠在吃;
也就是說當存在同名的成員變數與區域性變數時,在方法的內部訪問的是區域性變數,那是因為Java採取的是就近原則訪問的,要解決這個問題就需要使用this關鍵字;
2.存在同名成員變數與區域性變數的記憶體分析
(1)棧記憶體也叫方法棧,把它稱為方法棧的原因是因為:一個方法要執行的時候,JVM會在棧記憶體中開闢一片屬於這個方法的空間,讓這個方法在這片空間內執行;
(2)首先在這片程式碼中主方法會先執行,主方法一執行,JVM會在棧記憶體中開闢一片空間屬於main方法,在這片空間中先聲明瞭一個變數a,接著new一個Animal,這時候在堆記憶體中就建立了一個Animal物件,這個Animal有name和color兩個屬性,都分配了預設的初始值,name=“狗”,color=null;這時候假設它的記憶體地址是0X98,此時a這個變數就指向了0X98,也就是a指向了這個物件;
(3)接著在main方法的這片空間執行a.eat();eat方法執行的時候,JVM在棧記憶體中為這個方法開闢了一片屬於eat方法的空間,在這個eat方法裡首先聲明瞭一個變數name=“老鼠”,緊接著輸出語句,因為Java採取的是就近原則來訪問的,因為輸出語句中的name變數在eat方法這片空間也存在,如果存在它就只會在eat方法這片空間去找,如果這片空間沒有它才會去到堆記憶體中去找
3.定義:
(1)this關鍵字代表了所屬函式的呼叫者物件,this代表了物件的記憶體地址(在建構函式中列印this會發現結果是一個記憶體地址),也就是說哪個物件呼叫了this所在的函式,那麼this就指代哪個物件;
(2)this是指向本類中某一個物件的一個變數,this相當於文章中第一人稱的“我”,所有人描述自己的時候都會說“我”,只要讀“我”的這個人發生變化,這個“我”指向的人就變了;而this關鍵字與之類似,this是抽象的,剛開始並不知道是指代誰,this是每一個物件攜帶的變數,這個變數所指向的都是自己,this只是起到了一個描述的作用:只要有一個具體的物件來執行的時候,this就用這個物件的this,換一個物件,this就變成另一個物件的this,所以只有在執行的時候才知道指向誰。就像文章中的“我”,只有確定了誰是讀這篇文章的,才能確定這個“我”指代誰;
(3)this關鍵字代表的是物件的引用,也就是this在指向一個物件,所指向的物件就是呼叫該函式的物件引用;
4.this關鍵字的作用:
(1)如果存在同名的成員變數與區域性變數時,在方法內部預設是訪問區域性變數的資料,可以通過this關鍵字指定訪問成員變數的資料;
(2)在一個建構函式中可以呼叫另外一個建構函式初始化物件;
5.this關鍵字要注意的事項:
(1)存在同名的成員變數與區域性變數時,在方法的內部訪問的是區域性變數(Java採取的是“就近原則”的機制訪問的);
(2)如果在一個方法中訪問了一個變數,該變數只存在成員變數的情況下,那麼Java編譯器會在該變數的前面新增this關鍵字;
6.this關鍵字呼叫其他的建構函式要注意的事項:
(1)this關鍵字呼叫其他的建構函式時,this關鍵字必須要位於建構函式中的第一個語句;
(2)this關鍵字在建構函式中不能出現相互呼叫的情況,因為是一個死迴圈;
7.例項二:
class Student{
int id; //身份證
String name; //名字
public Student(int id,String name){//一個函式的形式引數也是屬於區域性變數
this(name); //呼叫了本類的一個引數的構造方法,根據傳入的引數確定呼叫的是本類的哪一個構造方法
this.id = id; //區域性變數的id給成員變數的id賦值
System.out.println("兩個引數的構造方法被呼叫了……");
}
public Student(){
System.out.println("無參的構造方法被呼叫了……");
}
public Student(String name){
this.name = name;
System.out.println("一個引數的構造方法被呼叫了……");
}
}
class Demo6{
public static void main(String[] args){
Student s = new Student(110,"鐵蛋");
System.out.println("編號:"+s.id+" 姓名:"+s.name);
}
}
執行結果如下圖所示:
注意:如果是this(); 代表呼叫了本類無參的構造方法。
8.例項三:
(1)需求:
使用Java定義一個人類,人具備id,name,age三個屬性,還具備一個比較年齡的方法;必須要寫上一個建構函式,建構函式也必須要使用this關鍵字。
class Person{
int id; //編號
String name; //姓名
int age; //年齡
//建構函式
public Person(int id,String name ,int age){
this.id = id;
this.name = name;
this.age = age;
}
//比較年齡的方法,這是本身就具備的,還有一個和誰比較是未知數
public void compareAge(Person p2){
if(this.age>p2.age){
System.out.println(this.name+"大!");
}else if(this.age<p2.age){
System.out.println(p2.name+"大!");
}else{
System.out.println("同齡");
}
}
}
class Demo7{
public static void main(String[] args) {
Person p1 = new Person(110,"狗娃",17);
Person p2 = new Person(119,"鐵蛋",9);
p1.compareAge(p2);
}
}
(2)執行結果如下圖所示:
二.super關鍵字
1. super關鍵字代表了父類空間的引用;
2. super關鍵字的作用:
(1) 子父類存在著同名的成員(包括變數和方法)時,在子類中預設是訪問子類的成員,可以通過super關鍵字指定訪問父類的成員;
(2) 建立子類物件時,預設會先呼叫父類無參的構造方法,可以通過super關鍵字指定呼叫父類的構造方法。
(1) 如果在子類的構造方法上沒有指定呼叫父類的構造方法,那麼java編譯器會在子類的構造方法內加上super()語句。
(2) super關鍵字呼叫父類的建構函式時,該語句必須要是子類建構函式中的第一個語句。
(3) super與this關鍵字不能同時出現在同一個建構函式中呼叫其他的建構函式。因為兩個語句都需要第一個語句。
(1) 代表的事物不一致。
① super關鍵字代表的是父類空間的引用。(並不能代表物件,只是代表一個物件中的一塊記憶體而已)
② this關鍵字代表的是所屬函式的呼叫者物件。
(2) 使用前提不一致。
① super關鍵字必須要有繼承關係才能使用。
② this關鍵字不需要存在繼承關係也可使用。
(3) 呼叫建構函式的區別:
① super關鍵字是呼叫父類的建構函式。
② this關鍵字是呼叫本類的建構函式。
3. super關鍵字呼叫父類構造方法要注意的事項:
注意:是兩個關鍵字不能同時出現在同一個建構函式中去呼叫其他的建構函式,裡面還是可以寫this.num = num。並不是說不能出現this。
4. super關鍵字與this關鍵字的區別:
5.例項:
class Father {
int x = 1;
Father() {
System.out.println("這是父類無參的構造方法");
}
Father(int x) {
this.x = x;
System.out.println("這是父類有參的構造方法");
}
void speak() {
System.out.println("我是父類");
}
}
class Son extends Father {
int y = 1;
Son() {
System.out.println("這是子類無參的構造方法");
}
Son(int y) {
this.y = y+x;
System.out.println("這是子類帶參的構造方法");
}
void run() {
super.speak(); //訪問父類的函式
System.out.println("我是子類");
}
}
class Demo1{
public static void main(String[] args) {
Son s = new Son(3);
System.out.println(s.y); //4
}
}
執行結果如下圖所示:
6.super關鍵字主要存在於子類方法中,用於指向子類物件中的父類物件;可以訪問父類的屬性、函式以及建構函式。