什么是Java構(gòu)造方法?Java構(gòu)造方法怎么定義?Java構(gòu)造方法怎么調(diào)用?Java構(gòu)造方法有什么作用?Java構(gòu)造方法可以重載嗎?接下來學(xué)習(xí)一下。
Java構(gòu)造方法是類中特殊的方法,通過調(diào)用構(gòu)造方法來完成對(duì)象的創(chuàng)建,以及對(duì)象屬性的初始化操作。
Java構(gòu)造方法怎么定義,請(qǐng)看以下的語法格式:
[修飾符列表] 構(gòu)造方法名(形式參數(shù)列表){
構(gòu)造方法體;
}
● 構(gòu)造方法名和類名一致。
● 構(gòu)造方法用來創(chuàng)建對(duì)象,以及完成屬性初始化操作。
● 構(gòu)造方法返回值類型不需要寫,寫上就報(bào)錯(cuò),包括void也不能寫。
● 構(gòu)造方法的返回值類型實(shí)際上是當(dāng)前類的類型。
● 一個(gè)類中可以定義多個(gè)構(gòu)造方法,這些構(gòu)造方法構(gòu)成方法重載。
怎么調(diào)用構(gòu)造方法呢,語法格式是:new 構(gòu)造方法名(實(shí)際參數(shù)列表);接下來,看以下代碼:
圖9-12:調(diào)用無參數(shù)構(gòu)造方法
以上程序運(yùn)行結(jié)果如下圖所示:
圖9-13:調(diào)用無參數(shù)構(gòu)造方法的運(yùn)行結(jié)果
以上程序的輸出結(jié)果中雖然第一行看不懂,但起碼說明程序是能夠正常執(zhí)行的。我們看到以上Date類當(dāng)中的代碼,并沒有發(fā)現(xiàn)任何構(gòu)造方法,為什么可以調(diào)用呢?接下來我們來測試一下,把構(gòu)造方法顯示的定義出來:
public class Date {
int year; //年
int month; //月
int day; //日
//構(gòu)造方法(無參數(shù)構(gòu)造方法)
public Date(){
System.out.println("Date類無參數(shù)構(gòu)造方法執(zhí)行");
}
}
public class DateTest {
public static void main(String[] args) {
System.out.println("main begin");
new Date();
System.out.println("main over");
}
}
運(yùn)行結(jié)果如下圖所示:
圖9-14:測試無參數(shù)構(gòu)造方法
通過以上程序執(zhí)行結(jié)果確實(shí)看到了“new Date()”確實(shí)調(diào)用了Date類當(dāng)中的無參數(shù)構(gòu)造方法。再看以下程序:
public class Date {
int year; //年
int month; //月
int day; //日
//構(gòu)造方法(有參數(shù)構(gòu)造方法)
public Date(int year){
System.out.println("帶有參數(shù)year的構(gòu)造方法");
}
}
public class DateTest {
public static void main(String[] args) {
System.out.println("main begin");
new Date();
System.out.println("main over");
}
}
編譯報(bào)錯(cuò)了,錯(cuò)誤信息如下圖所示:
圖9-15:編譯器錯(cuò)誤信息提示
通過以上的測試,得出這樣一個(gè)結(jié)論(這是java中語法的規(guī)定,記住就行):當(dāng)一個(gè)類沒有顯示的定義任何構(gòu)造方法的時(shí)候,系統(tǒng)默認(rèn)提供無參數(shù)構(gòu)造方法,當(dāng)顯示的定義構(gòu)造方法之后,系統(tǒng)則不再提供無參數(shù)構(gòu)造方法。無參數(shù)構(gòu)造方法又叫做缺省構(gòu)造器,或者默認(rèn)構(gòu)造方法。一般在開發(fā)中為了方便編程,建議程序員手動(dòng)的將無參數(shù)構(gòu)造方法寫上,因?yàn)椴粚憻o參數(shù)構(gòu)造方法的時(shí)候,這個(gè)默認(rèn)的構(gòu)造方法很有可能就不存在了,另外也是因?yàn)闊o參數(shù)構(gòu)造方法使用的頻率較高。例如以下代碼:
public class Date {
int year; //年
int month; //月
int day; //日
//構(gòu)造方法(無參數(shù)構(gòu)造方法)
public Date(){
System.out.println("Date類無參數(shù)構(gòu)造方法執(zhí)行");
}
//構(gòu)造方法(有參數(shù)構(gòu)造方法)
public Date(int year1){
System.out.println("帶有參數(shù)year的構(gòu)造方法");
}
//構(gòu)造方法(有參數(shù)構(gòu)造方法)
public Date(int year1 , int month1){
System.out.println("帶有參數(shù)year,month的構(gòu)造方法");
}
//構(gòu)造方法(有參數(shù)構(gòu)造方法)
public Date(int year1 , int month1 , int day1){
System.out.println("帶有參數(shù)year,month,day的構(gòu)造方法");
}
}
public class DateTest {
public static void main(String[] args) {
System.out.println("main begin");
new Date();
new Date(2008);
new Date(2008 , 8);
new Date(2008 , 8 , 8);
System.out.println("main over");
}
}
運(yùn)行結(jié)果如下圖所示:
圖9-16:調(diào)用所有構(gòu)造方法
通過以上的測試可以看出一個(gè)類當(dāng)中可以定義多個(gè)構(gòu)造方法,構(gòu)造方法是支持重載機(jī)制的,具體調(diào)用哪個(gè)構(gòu)造方法,那要看調(diào)用的時(shí)候傳遞的實(shí)際參數(shù)列表符合哪個(gè)構(gòu)造方法了。構(gòu)造方法雖然在返回值類型方面不寫任何類型,但它執(zhí)行結(jié)束之后實(shí)際上會(huì)返回該對(duì)象在堆內(nèi)存當(dāng)中的內(nèi)存地址,這個(gè)時(shí)候可以定義變量接收對(duì)象的內(nèi)存地址,這個(gè)變量就是之前所學(xué)的“引用”,請(qǐng)看以下代碼:
public class DateTest {
public static void main(String[] args) {
System.out.println("main begin");
Date time1 = new Date();
System.out.println(time1);
Date time2 = new Date(2008);
System.out.println(time2);
Date time3 = new Date(2008 , 8);
System.out.println(time3);
Date time4 = new Date(2008 , 8 , 8);
System.out.println(time4);
System.out.println("main over");
}
}
運(yùn)行結(jié)果如下圖所示:
圖9-17:構(gòu)造方法的返回值
以上程序中time1,time2,time3,time4都是引用,輸出這些引用的結(jié)果是“Date@xxxxx”,對(duì)于這個(gè)結(jié)果目前可以把它等同看做是對(duì)象的內(nèi)存地址(嚴(yán)格來說不是真實(shí)的對(duì)象內(nèi)存地址)。通過這個(gè)引用就可以訪問對(duì)象的內(nèi)存了,例如以下代碼:
public class DateTest {
public static void main(String[] args) {
System.out.println("main begin");
Date time1 = new Date();
System.out.println(time1.year + "年" + time1.month + "月" + time1.day + "日");
Date time2 = new Date(2008);
System.out.println(time2.year + "年" + time2.month + "月" + time2.day + "日");
Date time3 = new Date(2008 , 8);
System.out.println(time3.year + "年" + time3.month + "月" + time3.day + "日");
Date time4 = new Date(2008 , 8 , 8);
System.out.println(time4.year + "年" + time4.month + "月" + time4.day + "日");
System.out.println("main over");
}
}
運(yùn)行結(jié)果如下圖所示:
圖9-18:通過“引用”訪問屬性
為什么無論通過哪個(gè)構(gòu)造方法創(chuàng)建Date對(duì)象,最終的結(jié)果都是“0年0月0日”呢?這是因?yàn)樗械臉?gòu)造方法在執(zhí)行過程中沒有給對(duì)象的屬性手動(dòng)賦值,系統(tǒng)則自動(dòng)賦默認(rèn)值,實(shí)際上大部分情況下我們需要在構(gòu)造方法中手動(dòng)的給屬性賦值,這本來就是構(gòu)造方法的主要的職責(zé),要不然重載多次構(gòu)造方法就沒有意義了,以上的代碼應(yīng)該這樣寫,請(qǐng)看:
public class Date {
int year; //年
int month; //月
int day; //日
public Date(){
}
public Date(int year1){
year = year1;
}
public Date(int year1 , int month1){
year = year1;
month = month1;
}
public Date(int year1 , int month1 , int day1){
year = year1;
month = month1;
day = day1;
}
}
public class DateTest {
public static void main(String[] args) {
System.out.println("main begin");
Date time1 = new Date();
System.out.println(time1.year + "年" + time1.month + "月" + time1.day + "日");
Date time2 = new Date(2008);
System.out.println(time2.year + "年" + time2.month + "月" + time2.day + "日");
Date time3 = new Date(2008 , 8);
System.out.println(time3.year + "年" + time3.month + "月" + time3.day + "日");
Date time4 = new Date(2008 , 8 , 8);
System.out.println(time4.year + "年" + time4.month + "月" + time4.day + "日");
System.out.println("main over");
}
}
運(yùn)行結(jié)果如下圖所示:
圖9-19:通過構(gòu)造方法給屬性賦值
為什么第一個(gè)日期輸出的是“0年0月0日”?這是因?yàn)檎{(diào)用的是無參數(shù)構(gòu)造方法創(chuàng)建的第一個(gè)日期對(duì)象,在無參數(shù)構(gòu)造方法中沒有給屬性賦值,則系統(tǒng)賦默認(rèn)值,所以年月日都是0。那為什么第二個(gè)日期輸出的是“2008年0月0日”呢?這是因?yàn)檎{(diào)用的是“public Date(int year1){ year = year1; }”構(gòu)造方法創(chuàng)建的第二個(gè)日期對(duì)象,在這個(gè)構(gòu)造方法當(dāng)中只是顯示的給Date對(duì)象的year屬性賦值,month和day仍然是系統(tǒng)賦默認(rèn)值,所以month和day都是0。第三個(gè)日期對(duì)象是“2008年8月8日”,這是因?yàn)樵谶@個(gè)對(duì)應(yīng)的構(gòu)造方法中顯示的為year,month,day三個(gè)屬性都賦值了。在編寫以上構(gòu)造方法的時(shí)候需要注意變量名的問題,請(qǐng)看下圖:
圖9-20:java遵循就近原則
通過以上內(nèi)容的學(xué)習(xí)得知,構(gòu)造方法的作用是專門用來創(chuàng)建對(duì)象同時(shí)給屬性賦值的,它的語法很簡單,比普通方法還要簡單,因?yàn)闃?gòu)造方法名和類名一致,還不需要寫返回值類型,使用new就可以調(diào)用了。在一個(gè)類當(dāng)中可以同時(shí)定義多個(gè)構(gòu)造方法,它們之間構(gòu)成重載關(guān)系。這樣就做到了在java中你想要什么就new什么,每一次new都會(huì)在堆內(nèi)存中創(chuàng)建對(duì)象,并且對(duì)象內(nèi)部的實(shí)例變量被初始化了。
一定要注意,實(shí)例變量沒有手動(dòng)賦值的時(shí)候系統(tǒng)會(huì)默認(rèn)賦值,但不管是手動(dòng)賦值還是系統(tǒng)賦默認(rèn)值,都是在構(gòu)造方法執(zhí)行的時(shí)候才會(huì)進(jìn)行賦值操作,類加載的時(shí)候并不會(huì)初始化實(shí)例變量的空間,那是因?yàn)閷?shí)例變量是對(duì)象級(jí)別的變量,沒有對(duì)象,哪來實(shí)例變量,這也是為什么實(shí)例變量不能采用“類名”去訪問的原因。
public class DateTest {
public static void main(String[] args) {
System.out.println(Date.year);
}
}
編譯報(bào)錯(cuò)了:
圖9-21:實(shí)例變量不能直接采用“類名”訪問