this和super
構造方法
我們對封裝已經有了基本的了解,接下來我們來看一個新的問題白筹,依然以Person為例,由于Person中的屬性都被private了颠焦,外界無法直接訪問屬性何址,必須對外提供相應的set和get方法里逆。當創(chuàng)建Person對象的時候,Person對象一創(chuàng)建就要明確其姓名和年齡用爪,那該怎么做呢原押?
構造方法介紹
在開發(fā)中經常需要在創(chuàng)建對象的同時明確對象的屬性值,比如員工入職公司就要明確他的姓名偎血、年齡等屬性信息班眯。也就是在創(chuàng)建對象的時候就要做的事情,當使用new關鍵字創(chuàng)建對象時烁巫,怎么給對象的屬性初始化值呢署隘?這就要學習Java另外一門小技術,構造方法亚隙。
那什么是構造方法呢磁餐?從字面上理解就是對象創(chuàng)建時要執(zhí)行的方法。既然是對象創(chuàng)建時要執(zhí)行的方法阿弃,那么只要在new對象時诊霹,知道其執(zhí)行的構造方法是什么,就可以在執(zhí)行這個方法的時候給對象進行屬性賦值。
構造方法的格式:
修飾符 構造方法名(參數列表)
{
}
構造方法的體現
構造方法沒有返回值類型竹习。也不需要寫返回值性锭。因為它是為構建對象的,對象創(chuàng)建完鄙漏,方法就執(zhí)行結束。
構造方法名稱必須和類型保持一致棺蛛。
構造方法沒有具體的返回值怔蚌。
構造方法的代碼體現:
class Person {
// Person的成員屬性age和name
private int age;
private String name;
// Person的構造方法,擁有參數列表
Person(int a, String nm) {
// 接受到創(chuàng)建對象時傳遞進來的值旁赊,將值賦給成員屬性
age = a;
name = nm;
}
}
構造方法調用和內存圖解
理解構造方法的格式和基本功能之后桦踊,現在就要研究構造方法是怎么執(zhí)行的呢?在創(chuàng)建對象的時候是如何初始化的呢终畅?構造方法是專門用來創(chuàng)建對象的籍胯,也就是在new對象時要調用構造方法。現在來看看如何調用構造方法离福。
class Person {
// Person的成員屬性age和name
private int age;
private String name;
// Person的構造方法杖狼,擁有參數列表
Person(int a, String nm) {
// 接受到創(chuàng)建對象時傳遞進來的值,將值賦給成員屬性
age = a;
name = nm;
}
public void speak() {
System.out.println("name=" + name + ",age=" + age);
}
}
class PersonDemo {
public static void main(String[] args) {
// 創(chuàng)建Person對象术徊,并明確對象的年齡和姓名
Person p2 = new Person(23, "張三");
p2.speak();
}
}
上述代碼演示了創(chuàng)建對象時構造方法的調用本刽。即在創(chuàng)建對象時,會調用與參數列表對應的構造方法。
上述代碼的圖解:
圖解說明:
1子寓、首先會將main方法壓入棧中暗挑,執(zhí)行main方法中的 new Person(23,"張三");
2、在堆內存中分配一片區(qū)域斜友,用來存放創(chuàng)建的Person對象炸裆,這片內存區(qū)域會有屬于自己的內存地址(0x88)。然后給成員變量進行默認初始化(name=null鲜屏,age=0)烹看。
3、執(zhí)行構造方法中的代碼(age = a ; name = nm;),將變量a對應的23賦值給age洛史,將變量nm對應的”張三賦值給name惯殊,這段代碼執(zhí)行結束后,成員變量age和name的值已經改變也殖。執(zhí)行結束之后構造方法彈棧土思,Person對象創(chuàng)建完成。將Person對象的內存地址0x88賦值給p2忆嗜。
默認構造方法和細節(jié)
如果沒有顯示指定構造方法己儒,當在編譯Java文件時,編譯器會自動給class文件中添加默認的構造方法捆毫。如果在描述類時闪湾,我們顯示指定了構造方法,那么绩卤,當在編譯Java源文件時途样,編譯器就不會再給class文件中添加默認構造方法。
class Person {
//如果沒有顯示指定構造方法省艳,編譯會在編譯時自動添加默認的構造方法
//Person(){} //空參數的默認構造方法
}
當在描述事物時娘纷,要不要在類中寫構造方法呢?這時要根據描述事物的特點來確定跋炕,當描述的事物在創(chuàng)建其對象時就要明確屬性的值,這時就需要在定義類的時候書寫帶參數的構造方法律适。若創(chuàng)建對象時不需要明確具體的數據辐烂,這時可以不用書寫構造方法(不書寫也有默認的構造方法)。
構造方法的細節(jié):
1捂贿、一個類中可以有多個構造方法纠修,多個構造方法是以重載的形式存在的
2、構造方法是可以被private修飾的厂僧,作用:其他程序無法創(chuàng)建該類的對象扣草。
class Person {
private int age;
private String name;
// 私有無參數的構造方法,即外界不能通過new Person();語句創(chuàng)建本類對象
private Person() {
}
// 多個構造方法是以重載的形式存在
Person(int a) {
age = a;
}
Person(String nm, int a) {
name = nm;
age = a;
}
}
構造方法和一般方法區(qū)別
構造方法在對象創(chuàng)建時就執(zhí)行了,而且只執(zhí)行一次辰妙。一般方法是在對象創(chuàng)建后鹰祸,需要使用時才被對象調用,并可以被多次調用密浑。
問題:有了構造方法之后可以對對象的屬性進行初始化蛙婴,那么還需要對應的set和get方法嗎?需要相應的set和get方法尔破,因為對象在創(chuàng)建之后需要修改和訪問相應的屬性值時街图,在這時只能通過set或者get方法來操作。
思考懒构,如下代碼有問題嗎餐济?
class Person {
void Person() {//void有問題
}
}
class PersonDemo {
public static void main(String[] args) {
Person p = new Person();
}
}
this關鍵字
在之前學習方法時,我們知道方法之間是可以相互調用的胆剧,那么構造方法之間能不能相互調用呢颤介?若可以,怎么調用呢赞赖?
this調用構造方法
在之前學習方法之間調用時滚朵,可以通過方法名進行調用∏坝颍可是針對構造方法辕近,無法通過構造方法名來相互調用。構造方法之間的調用匿垄,可以通過this關鍵字來完成移宅。
構造方法調用格式:
this(參數列表);
構造方法的調用
class Person {
// Person的成員屬性
private int age;
private String name;
// 無參數的構造方法
Person() {
}
// 給姓名初始化的構造方法
Person(String nm) {
name = nm;
}
// 給姓名和年齡初始化的構造方法
Person(String nm, int a) {
// 由于已經存在給姓名進行初始化的構造方法 name = nm;因此只需要調用即可
// 調用其他構造方法,需要通過this關鍵字來調用
this(nm);
// 給年齡初始化
age = a;
}
}
this的原理圖解
了解了構造方法之間是可以相互調用椿疗,那為什么他們之間通過this就可以調用呢漏峰?通過上面的學習,簡單知道使用this可以實現構造方法之間的調用届榄,但是為什么就會知道this調用哪一個構造方法呢浅乔?接下來需要圖解完成。
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);
}
}
圖列說明:
1铝条、先執(zhí)行main方法靖苇,main方法壓棧,執(zhí)行其中的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,這時會執(zhí)行其中name = nm谋梭,即把“張三”賦值給成員的name信峻。當賦值結束后Person(String nm , int a)構造方法彈棧。
5瓮床、程序繼續(xù)執(zhí)行構造方法(Person(String nm , int a)中的age = a盹舞;這時會將23賦值給成員屬性age。賦值結束構造方法(Person(String nm , int a)彈棧隘庄。
6踢步、當構造方法(Person(String nm , int a)彈棧結束后,Person對象在內存中創(chuàng)建完成丑掺,并將0x33賦值給main方法中的p引用變量获印。
this到底代表什么呢?this代表的是對象街州,具體代表哪個對象呢兼丰?哪個對象調用了this所在的方法,this就代表哪個對象唆缴。
調用其他構造方法的語句必須定義在構造方法的第一行鳍征,原因是初始化動作要最先執(zhí)行。
成員變量和局部變量同名問題
通過上面學習面徽,基本明確了對象初始化過程中的細節(jié)艳丛,也知道了構造方法之間的調用是通過this關鍵字完成的。但this也有另外一個用途斗忌,當在方法中出現了局部變量和成員變量同名的時候质礼,那么在方法中怎么區(qū)別局部變量成員變量呢?可以在成員變量名前面加上this.來區(qū)別成員變量和局部變量织阳。
class Person {
private int age;
private String name;
// 給姓名和年齡初始化的構造方法
Person(String name, int age) {
// 當需要訪問成員變量是,只需要在成員變量前面加上this.即可
this.name = name;
this.age = age;
}
public void speak() {
System.out.println("name=" + this.name + ",age=" + this.age);
}
}
class PersonDemo {
public static void main(String[] args) {
Person p = new Person("張三", 23);
p.speak();
}
}
this的應用
學習完了構造方法砰粹、this的用法之后唧躲,現在做個小小的練習造挽。需求:在Person類中定義功能,判斷兩個人是否是同齡人
class Person {
private int age;
private String name;
// 給姓名和年齡初始化的構造方法
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;
}
}
super關鍵字
子父類中構造方法的調用
在創(chuàng)建子類對象時,父類的構造方法會先執(zhí)行肛真,因為子類中所有構造方法的第一行有默認的隱式super();語句谐丢。
格式:
//調用本類中的構造方法
this(實參列表);
//調用父類中的空參數構造方法
super();
//調用父類中的有參數構造方法
super(實參列表);
為什么子類對象創(chuàng)建都要訪問父類中的構造方法?因為子類繼承了父類的內容蚓让,所以創(chuàng)建對象時乾忱,必須要先看父類是如何對其內容進行初始化的,看如下程序:
public class Test {
public static void main(String[] args) {
new Zi();
}
}
class Fu{
int num ;
Fu(){
System.out.println("Fu構造方法"+num);
num = 4;
}
}
class Zi extends Fu{
Zi(){
//super(); 調用父類空參數構造方法
System.out.println("Zi構造方法"+num);
}
}
// 執(zhí)行結果:
// Fu構造方法0
// Zi構造方法4
通過結果發(fā)現历极,子類構造方法執(zhí)行時中窄瘟,調用了父類構造方法,這說明趟卸,子類構造方法中有一句super()蹄葱。那么,子類中的構造方法為什么會有一句隱式的super()呢锄列?
原因:子類會繼承父類中的內容图云,所以子類在初始化時,必須先到父類中去執(zhí)行父類的初始化動作邻邮。這樣竣况,才可以使用父類中的內容。
當父類中沒有空參數構造方法時饶囚,子類的構造方法必須有顯示的super語句帕翻,指定要訪問的父類有參數構造方法。
子類對象創(chuàng)建過程的細節(jié)
如果子類的構造方法第一行寫了this調用了本類其他構造方法萝风,那么super調用父類的語句還有嗎嘀掸?這時是沒有的,因為this()或者super(),只能定義在構造方法的第一行规惰,因為初始化動作要先執(zhí)行睬塌。
父類構造方法中是否有隱式的super呢?也是有的歇万。記卓纭:只要是構造方法默認第一行都是super();
父類的父類是誰呢?super調用的到底是誰的構造方法呢贪磺?Java體系在設計硫兰,定義了一個所有對象的父類Object
類中的構造方法默認第一行都有隱式的super()語句,用來訪問父類中的空參數構造方法寒锚。所以父類的構造方法既可以給自己的對象初始化劫映,也可以給自己的子類對象初始化违孝。如果默認的隱式super()語句在父類中沒有對應的構造方法,那么必須在構造方法中通過this或者super的形式明確要調用的構造方法泳赋。
super應用
練習:描述學生和工人這兩個類雌桑,將他們的共性name和age抽取出來存放在父類中,并提供相應的get和set方法祖今,同時需要在創(chuàng)建學生和工人對象就必須明確姓名和年齡
//定義Person類校坑,將Student和Worker共性抽取出來
class Person {
private String name;
private int age;
public Person(String name, int age) {
// super();
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;
}
}
class Student extends Person {
// Student類的構造方法
Student(String name, int age) {
// 使用super關鍵字調用父類構造方法,進行相應的初始化動作
super(name, age);
}
public void study() {// Studnet中特有的方法
System.out.println(this.getName() + "同學在學習");
}
}
class Worker extends Person {
Worker(String name, int age) {
// 使用super關鍵字調用父類構造方法千诬,進行相應的初始化動作
super(name, age);
}
public void work() {// Worker 中特有的方法
System.out.println(this.getName() + "工人在工作");
}
}
public class Test {
public static void main(String[] args) {
Student stu = new Student("小明",23);
stu.study();
Worker w = new Worker("小李",45);
w.work();
}
}
知識點總結
this關鍵字
this關鍵字耍目,本類對象的引用
this是在方法中使用的,哪個對象調用了該方法大渤,那么制妄,this就代表調用該方法的對象引用
this什么時候存在的?當創(chuàng)建對象的時候泵三,this存在的
this的作用:用來區(qū)別同名的成員變量與局部變量(this.成員變量)
public void setName(String name) {
this.name = name;
}
構造方法: 用來給類的成員進行初始化操作
格式:
修飾符 類名 (參數列表) {
...
}
構造方法的特點:
方法名與類名相同
沒有返回值耕捞,也沒有返回值類型,連void也沒有
只有在創(chuàng)建對象的時候才可以被調用
super關鍵字
super指的是父類的存儲空間(理解為父類的引用)
調用父類的成員變量:super.成員變量;
調用父類的構造方法:super(參數);
調用父類的成員方法:super.成員方法();
繼承中的構造方法注意事項:
如果我們手動給出了構造方法烫幕,編譯器不會在給我們提供默認的空參數構造方法
如果我們沒寫任何的構造方法俺抽,編譯器提供給我們一個空參數構造方法
在構造方法中,默認的第一條語句為 super();它是用來訪問父類中的空參數構造方法较曼,進行父類成員的初始化操作
當父類中沒有空參數構造方法的時候磷斧, 可以通過 super(參數) 訪問父類有參數的構造方法; 也可以通過 this(參數) 訪問本類中其他構造方法捷犹,前提是本類中的其他構造方法已經能夠正常訪問父類構造方法弛饭;
super(參數) 與 this(參數) 不能同時在構造方法中存在。
(更多相關java知識干貨萍歉,關注“軟帝在線”公眾號獲取相關福利)