類的構造函數
構造函數在每個類中都存在,是面向對象設計語言(OOP)的特色。
特點:
- 函數名與類名是相同的
- 不能有返回值
- 可以有參數,也可以沒有參數
- 可以有多個
說明:
- 聲明一個對象,系統首先爲該對象分配內存,然後立即自動調用該對象的構造函數
注意:
- 任何一個類對象被生成時候一定會調用該類的構造函數
- 無論一個類有多少個構造函數,生成一個類對象時一定只會調用其中的某一個構造函數!
class A
{
int i;
int j;
}
class TestMemo
{
public static void main(String[] args)
{
A aa = new A();
//運行此語句時,
//首先
//->(A *)malloc(sizeof(A));
//->new A();在堆中動態分配一塊區域,被當作了A對象
//->aa本身的內存是在棧中分配的
//其次
//調用系統默認分配的class A()這個無形參的構造函數
//堆中內存的地址賦給了aa
//aa指向堆中的內存,aa代表了堆中的內存
//aa.i代表:aa這個靜態指針變量所指向的動態內存中的A對象數據成員i
//
aa.i = 10;
aa.j = 20;
System.out.printf("%d, %d\n",aa.i,aa.j);
}
}
_________________________
程序運行示例:
10, 20
_________________________
這個程序表面上沒有構造函數(實際上你懂的),但是程序可以正常運行。這是因爲若沒有人爲的創建的構造函數,系統會自動爲該程序創建無參構造函數
一旦人爲的創建構造函數,系統就不再會自動爲該程序創建無參構造函數
class A
{
int i;
int j;
public A(int a,int b)
{ //此處認爲創建有參數的構造函數,系統就不再會爲程序自動創建無參構造函數
System.out.printf("有參構造函數被調用了!");
}
}
class TestMemo
{
public static void main(String[] args)
{
A aa = new A();//(A *)malloc(sizeof(A));
//new A();在堆中動態分配一塊區域,被當作了A對象
//aa本身的內存是在棧中分配的
//堆中內存的地址賦給了aa
//aa指向堆中的內存,aa代表了堆中的內存
//aa.i代表:aa這個靜態指針變量所指向的動態內存中的A對象數據成員i
aa.i = 10;
aa.j = 20;
System.out.printf("%d, %d\n",aa.i,aa.j);
}
}
程序運行示例:
————————————————————————————————————
TestMemo.java:18: 錯誤: 無法將類 A中的構造器 A應用到給定類型;
A aa = new A();//(A *)malloc(sizeof(A));
^
需要: int,int
找到: 沒有參數
原因: 實際參數列表和形式參數列表長度不同
1 個錯誤
————————————————————————————————————
該程序就充分表現了一旦人爲創建構造函數,系統就不再創建,可以理解系統是一個特立獨行的人,別人幹過的事情,它絕不會再幹。
class A
{
private int i;
private int j;
/**
public B(int a,int b) /*error 函數名與類名必須是相同的*/
public void A(int a,int b) /*error ,構造函數不能有返回值,這是類A的一個普通的操作,不再是構造函數*/
*/
public A()
{
System.out.printf("一個類的構造函數可以有多個\n");
}
public A(int a,int b)
{
i = a;
j = b;
System.out.printf("有參構造函數被調用了!\n");
}
public void show()
{
System.out.printf("i = %d,j = %d\n",i,j);
}
}
class Main
{
public static void main(String[] args)
{
A aa = new A(1,2); //此處創建對象aa的同時,系統還會調用有參的構造函數public A(int a,int b)
A bb = new A(); //此處創建對象bb的同時,系統還會調用無參的構造函數 public A()
aa.show();
}
}
程序運行示例:
————————————————————————————————————
有參構造函數被調用了!
一個類的構造函數可以有多個
i = 1,j = 2
————————————————————————————————————
構造函數,只有構造此類對象的時候會調用!
幾點要求:
1、此構造函數沒有返回值,故嚴格上講,不能稱之爲函數,void也不能加
2、一個類的構造函數可以有很多個,在類創建對象時候,根據A aa = new A( );中的
括號中形式參數的個數來匹配相應的構造函數
擴展補充
構造函數的返回值問題
-
在一個類中可以定義多個函數名與類名相同卻有返回值的函數,函數爲void或者int或者double都是可以的,
這些有返回值的函數只要能滿足重載特點,就可以同時存在一個類中,不過要注意:這些有返回值的函數(包括返回值爲void的函數)都不是構造函數,都不會像創建對象的同時調用構造函數那樣被類對象自動調用。
-
當然也可以定義多個沒有返回值的函數,注意連void都不可以加,這些函數纔是構造函數,無返回值的函數纔會被對象自動調用。
-
如果定義了有返回值並且方法名與類名相同的方法(類中的操作),程序並不會報錯,但是容易產生歧義,所以強烈建議不要在構造函數的前面加返回值
構造函數數據成員的賦值問題
-
如果在定義的同時沒有初始化,則它的值時系統自動分配好的默認值!
-
如果在定義數據成員的同時賦初值,則是可以的,也就是說該值是生效的,注意在C++中則不可以,在C++中一個類的數據成員不能在定義的同時初始化,它只能在構造函數中初始化
-
如果在定義數據成員的同時賦初值,當然生效,但如果在構造函數中又改變了定義時賦的初值,則該數據成員最終的值就是構造函數中修改之後的那個值,因爲:系統先執行定義時賦的初值,然後再執行構造函數中賦的初值