this關鍵字、super關鍵字、final關鍵字、static關鍵字
1、this關鍵字
(1)功能:
------------------------(一)呼叫本類中的屬性,也就是成員變數。哪個物件呼叫了this所在函式,this就代表哪個物件。
------------------------(二)呼叫本類中的其他方法
------------------------(三)呼叫本類中的其他構造方法,呼叫時要放在構造方法的首行
public class TestThis { public static void main(String[] args) { Person2 p = new Person2(10,"daming"); p.show(); Person2 p1= new Person2(20); p1.show(); } } public class Person2{ private int age; private String name; public Person2(){ System.out.println("呼叫了無參建構函式"); } public Person2(int a){ this(); age = a; System.out.println("呼叫了有參建構函式包含年齡"+"age="+age); } public Person2(int a,String n){ this(a); age = a; name = n; System.out.println("呼叫了有參建構函式包含年齡和名稱"+"age="+age+"--"+"name="+name); } public void show(){ System.out.println("呼叫了有參建構函式void---"+"age="+age+"--"+"name="+name); } } /* p.show(); 呼叫了無參建構函式 呼叫了有參建構函式包含年齡age=10 呼叫了有參建構函式包含年齡和名稱age=10--name=daming 呼叫了有參建構函式void---age=10--name=daming p1.show(); 呼叫了無參建構函式 呼叫了有參建構函式包含年齡age=20 呼叫了有參建構函式void---age=20--name=null*/
(2)呼叫構造方法
構造方法之間的呼叫,可以通過this關鍵字來完成。
構造方法呼叫格式:
this(引數列表);
package demo03; public class Person { private String name; private int age; //空參構造 public Person(){ } // 給姓名初始化的構造方法 public Person(String nm){ name = nm; } // 給姓名和年齡初始化的構造方法 public Person(String nm, int a) { // 由於已經存在給姓名進行初始化的構造方法 name = nm; //因此只需要呼叫即可 // 呼叫其他構造方法,需要通過this關鍵字來呼叫 this(nm); // 給年齡初始化 age = a; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
package demo03; public class Test { public static void main(String[] args) { Person a = new Person("a",2); a.setAge(1); System.out.println(a.getAge()+a.getName()); } }
this原理圖解:
Public class Person { private int age; private String name; Person() { } Person(String nm) { name = nm; } Person(String nm, int a) { this(nm); age = a; } } class PersonDemo { public static void main(String[] args) { Person p = new Person("張三", 23); } }
圖例解釋:
(自己的理解)先執行main方法,main方法壓棧,然後執行new person()
看到new一個物件,就在堆中劃出一塊區域,分配記憶體地址,接著成員變數預設值初始化;
構造方法Person(String nm , int a))壓棧,將“張三”傳遞給nm,23傳給age,當賦值結束後,Person(String nm , int a)彈棧。
Person物件在記憶體中建立完成,並將0x33賦值給main方法中的p引用變數。
官方解釋:
1、先執行main方法,main方法壓棧,執行其中的new Person(“張三”,23);
2、堆記憶體中開闢空間,併為其分配記憶體地址0x33,,緊接著成員變數預設初始化(name=null age = 0);
3、擁有兩個引數的構造方法(Person(String nm , int a))壓棧,在這個構造方法中有一個隱式的this,因為構造方法是給物件初始化的,那個物件呼叫到這個構造方法,this就指向堆中的那個物件。
4、由於Person(String nm , int a)構造方法中使用了this(nm);構造方法Person(String nm)就會壓棧,並將“張三”傳遞給nm。在Person(String nm , int a)構造方法中同樣也有隱式的this,this的值同樣也為0x33,這時會執行其中name = nm,即把“張三”賦值給成員的name。當賦值結束後Person(String nm , int a)構造方法彈棧。
5、程式繼續執行構造方法(Person(String nm , int a)中的age = a;這時會將23賦值給成員屬性age。賦值結束構造方法(Person(String nm , int a)彈棧。
6、當構造方法(Person(String nm , int a)彈棧結束後,Person物件在記憶體中建立完成,並將0x33賦值給main方法中的p引用變數。
this代表什麼:
this代表的是物件,具體代表哪個物件呢?哪個物件呼叫了this所在的方法,this就代表哪個物件。
呼叫其他構造方法的語句必須定義在構造方法的第一行,原因是初始化動作要最先執行。
(3)成員變數與區域性變數同名問題:可以在成員變數名前面加上this.來區別成員變數和區域性變數
public class Person { private int age; private String name; // 給姓名和年齡初始化的構造方法 public Person(String name, int age) { // 當需要訪問成員變數是,只需要在成員變數前面加上this.即可 this.name = name; this.age = age; } public void speak() { System.out.println("name=" + this.name + ",age=" + this.age); } }
public class PersonDemo { public static void main(String[] args) { Person p = new Person("張三", 23); p.speak(); } }
this應用:
package demo05; public class Person { private int age; private String name; // 給姓名和年齡初始化的構造方法 public Person(String name, int age) { // 當需要訪問成員變數是,只需要在成員變數前面加上this.即可 this.name = name; this.age = age; } public void speak() { System.out.println("name=" + this.name + ",age=" + this.age); } // 判斷是否為同齡人 public boolean equalsAge(Person p) { // 使用當前呼叫該equalsAge方法物件的age和傳遞進來p的age進行比較 // 由於無法確定具體是哪一個物件呼叫equalsAge方法,這裡就可以使用this來代替 /* * if(this.age == p.age) { return true; } return false; */ return this.age == p.age; } }
public class Teat { public static void main(String[] args) { Person a=new Person("張三",18); a.speak(); Person b=new Person("李四",20); b.speak(); boolean bs=a.equalsAge(b);//-----------------------------------------比較 System.out.println(bs); } }
2、super關鍵字
(1)子父類中構造方法的呼叫
格式:
呼叫本類中的構造方法
this(實參列表);
呼叫父類中的空引數構造方法
super();
呼叫父類中的有引數構造方法
super(實參列表);
例如:
為什麼子類物件建立都要訪問父類中的構造方法?因為子類繼承了父類的內容,所以建立物件時,必須要先看父類是如何對其內容進行初始化的,看如下程式:
public class Fu{ int num ; public Fu(){ System.out.println("Fu構造方法"+num);//-----------------------------------------------------------------空參構造 num = 4; } }
public class Zi extends Fu{ public Zi(){ //super(); 呼叫父類空引數構造方法 System.out.println("Zi構造方法"+num);//------------------------------------------------------------------- } }
public class Test { public static void main(String[] args) { new Zi();//----------------------------------------------------------------------------------------------- } }
子類構造方法執行時中,呼叫了父類構造方法,這說明,子類構造方法中有一句super()。
子類會繼承父類中的內容,所以子類在初始化時,必須先到父類中去執行父類的初始化動作。這樣,才可以使用父類中的內容。
當父類中沒有空引數構造方法時,子類的構造方法必須有顯示的super語句,指定要訪問的父類有引數構造方法。
子類物件建立中的注意點:
一、如果子類的構造方法第一行寫了this呼叫了本類其他構造方法,那麼super呼叫父類的語句是沒有的。
因為this()或者super(),只能定義在構造方法的第一行,因為初始化動作要先執行。
二、父類構造方法中有隱式的super,只要是構造方法預設第一行都是super();
三、super呼叫的是所有物件的父類Object構造方法(Java體系在設計,定義了一個所有物件的父類Object)
注意:
類中的構造方法預設第一行都有隱式的super()語句,在訪問父類中的空引數構造方法。所以父類的構造方法既可以給自己的物件初始化,也可以給自己的子類物件初始化。
如果預設的隱式super()語句在父類中沒有對應的構造方法,那麼必須在構造方法中通過this或者super的形式明確要呼叫的構造方法。
練習:
練習:描述學生和工人這兩個類,將他們的共性name和age抽取出來存放在父類中,並提供相應的get和set方法,同時需要在建立學生和工人物件就必須明確姓名和年齡
package lianxi2; public class Person { private String name; private int age; public Person(String name,int age){ this.name=name; this.age=age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } }
package lianxi2; public class Student extends Person{ //Student類的構造方法 public Student(String name,int age){ // 使用super關鍵字呼叫父類構造方法,進行相應的初始化動作 super(name,age); } public void study(){ System.out.println(this.getName()+"同學正在學習"); } }
package lianxi2; public class Worker extends Person{ public Worker(String name, int age){ // 使用super關鍵字呼叫父類構造方法,進行相應的初始化動作 super(name, age); } public void work(){ System.out.println(this.getName() + "工人在工作"); } }
package lianxi2; public class Test { public static void main(String[] args) { Student stu = new Student("小明",23); stu.study(); Worker w = new Worker("小李",45); w.work(); } }
3、final關鍵字
(1)final 關鍵字的概述:
類中的部分方法功能是固定的,不想讓子類重寫。可是當子類繼承了這些特殊類之後,就可以對其中的方法進行重寫,要解決這個問題(讓子類無法對父類中的某一方法進行重寫)
需要使用到一個關鍵字final,final的意思為最終,不可變。final是個修飾符,它可以用來修飾類,類的成員,以及區域性變數。不能修飾構造方法。
(2)final的特點:
---------------------final修飾類不可以被繼承,但是可以繼承其他類。
例如:
public class person {}//定義一個person類 public final class Fu extends person{} //定義一個父類,繼承了person類 public class Zi extends Fu{} //定義子類,因為父類中使用了final所以不能繼承Fu類
------------------- final修飾的方法不可以被子類重寫,但父類中沒有被final修飾方法,子類重寫後可以加final。
例如:
Public class Fu { //=================================定義父類 // final修飾的方法,不可以被覆蓋,但可以繼承使用 public final void method1(){}//====================應用了final修飾的method1 public void method2(){}//==========================定義一個方法method2 }
Public class Zi extends Fu {//====================定義一個子類,繼承了父類的方法(method1沒有被繼承,無法重寫,因為method1方法應用了final修飾) //重寫method2方法 public final void method2(){}//==================重寫method2 }
--------------------------------final修飾的變數稱為常量,這些變數只能賦值一次。而且終身不變。
例如:
final int i = 20; i = 30; //賦值報錯,final修飾的變數只能賦值一次,一次賦值,終生不變
------------------------------ 引用型別的變數值為物件地址值,地址值不能更改,但是地址內的物件屬性值可以修改。(也是一次賦值終生不變)
例如:
final Person p = new Person();
Person p2 = new Person();
p = p2; //final修飾的變數p,所記錄的地址值不能改變
p.name = "小明";//可以更改p物件中name屬性值
Person p2 = new Person();
p = p2; //final修飾的變數p,所記錄的地址值不能改
p.name = "小明";//可以更改p物件中name屬性值
----------------------------------- 修飾成員變數,需要在建立物件前賦值,否則報錯。(當沒有顯式賦值時,多個構造方法的均需要為其賦值。)
例如:
public class Demo { //直接賦值 final int m = 100; //final修飾的成員變數,需要在建立物件前賦值,否則報錯。 final int n; public Demo(){ //可以在建立物件時所呼叫的構造方法中,為變數n賦值 n = 2016; } }
final應用舉例:
//final修飾類(太監類) //不能被繼承,但可以繼承其他類 public final class Fu { }
public class Fu2 { public final void xiuche(){ System.out.println("失傳的修車手藝"); } public void maiche(){ System.out.println("這是祖傳的買車手藝"); } }
public class Zi extends Fu2{ public final void maiche(){ System.out.println("失傳的mai車手藝"); } }
public class Zi2 { public void eat(){ final int i; i=3; //final Fu2 f=new Fu2(); Fu2 f=new Fu2(); f=null; } }
//被final修飾的成員變數沒有預設賦值 public class Zi3 { final String name="小明";//必須賦值 }
4、static關鍵字
(1)static關鍵字概述:
-----------------------------不建立物件,就可以呼叫方法,可以通過static關鍵字來實現。static它是靜態修飾符,一般用來修飾類中的成員。
(2)static的特點:
-------------被static修飾的成員變數屬於類,不屬於這個類的某個物件。
(也就是說,多個物件在訪問或修改static修飾的成員變數時,其中一個物件將static成員變數值進行了修改,其他物件中的static成員變數值跟著改變,即多個物件共享同一個static成員變數)
舉例說明:
public class Demo { public static int num = 100;//==========================被static修飾過 }
public class Test { public static void main(String[] args) { Demo d1 = new Demo(); Demo d2 = new Demo(); d1.num = 200; System.out.println(d1.num); //結果為200 System.out.println(d2.num); //結果為200 }//============================================其中一個更改了結果,所有的就都改過來了所以結果為200 }
-------------------------------------被static修飾的成員可以並且建議通過類名直接訪問。
例如:
public class Student { String name; int age; static String schoolname; }
public class Test { public static void main(String[] args) { Student s=new Student(); s.name="小紅"; s.age=18; Student.schoolname="背景大學";//本來按照平時習慣應該是s.schoolname="背景大學",但被static修飾過所以建議改成直接用類名訪問 Student s2=new Student(); s2.name="小明"; s2.age=18; Student.schoolname="清華大學"; System.out.println(Student.schoolname+"..."+Student.schoolname); } }
注意:
--------------------------------- 靜態內容是優先於物件存在,只能訪問靜態,不能使用this/super。靜態修飾的內容存於靜態區。
- -------------------------------同一個類中,靜態成員只能訪問靜態成員
---- ---------------------------- main方法為靜態方法僅僅為程式執行入口,它不屬於任何一個物件,可以定義在任意類中。
---------------------------------多型呼叫方法中,編譯看=左邊,父類有,編譯成功,父類沒有,編譯失敗
執行,靜態方法,執行父類中的靜態方法,
執行,非靜態方法,執行子類的重寫方法
成員變數,編譯執行全是父類
定義靜態常量時:
在類中定義一個靜態常量,通常使用public static final修飾的變數來完成定義。此時變數名用全部大寫,多個單詞使用下劃線連線。
定義格式:
public static final 資料型別 變數名 = 值;
例如:
class School { public static final String SCHOOL_NAME = "北京大學"; public static void method(){ System.out.println("一個靜態方法"); } }
當我們想使用類的靜態成員時,不需要建立物件,直接使用類名來訪問即可
System.out.println(School.SCHOOL_NAME); School.method(); // 呼叫一個靜態方法
介面中的每個成員變數都預設使用public static final修飾。
所有介面中的成員變數已是靜態常量,由於介面沒有構造方法,所以必須顯示賦值。可以直接用介面名訪問。
interface Inter { public static final int COUNT = 100; }
訪問介面中的靜態變數
Inter.COUNT