構造器定義
構造器是用來初始化類實例。在對象編程語言中,一般在定義了一個類型之後,爲了能使用它,必須把這個類型具體化,也就是指定爲一個具體的對象。而構造函數就是從定義出發,建立與定義相對應的對象。用計算機語言來說,光有定義是不能使用,必須通過構造函數來分配內存空間給可使用的對象。
構造器的聲明語法
<作用域> <類名> (<參數列表>){
<方法體>
}
構造器的使用規則
- 構造器的名稱始終與其類名相同
- 一個類可以有多個構造器
- 構造器可以有0、1個或多個參數
- 構造器始終使用new關鍵字進行調用
- 構造器沒有返回值
構造方法與成員方法的區別
- 修飾符不同
構造方法只能使用public、private、protected訪問修飾符,而不能使用static、final、synchronized、abstract等非訪問修飾符。這是因爲構造方法用於初始化一個實例對象,所以static修飾是沒有任何意義的;多個線程不會同時創建內存地址相同的同一個對象,所以synchronized修飾沒有意義;構造方法不能被子類繼承,所以final和abstract修飾沒有意義。 - 返回值不同
構造方法沒有返回值。 - 構造方法名與類名相同。
缺省構造器
- 每個類至少有一個構造器
- 如果你沒有手工編寫一個構造器,則系統在編譯時自動添加一個缺省構造器
public class A {
public static void main(String[] args) {
A a = new A();//調用系統默認的無參構造器
}
}
- 一旦自己定義了自己的構造函數java就會收回自己的默認構造函數,因此建議自己要書寫無參構造函數。
public class A {
public A(String name){
System.out.println(name);
}
public static void main(String[] args) {
//A a = new A();//報錯,因爲沒有相應的無參構造函數的定義
A a2 = new A("a2");//輸出結果爲:a2
}
}
構造器不能被繼承
- 子類繼承父類所有的成員方法和成員變量
- 但子類不繼承父類的構造器。
調用其他構造器
- 調用父類構造器用super()方法
使用super可以調用父類的構造器
public class A {
public A(){
System.out.println("A--無參構造器");
}
public A(String name){
System.out.println("A--有參構造器:"+name);
}
}
public class B extends A{
public B(){
super();
System.out.println("B--無參構造器");
}
public B(String name){
super(name);
System.out.println("B--有參構造器:"+name);
}
public static void main(String[] args) {
B b1 = new B();
System.out.println("--------------");
B b2 = new B("b2");
}
}
//輸出結果爲:
/*
A--無參構造器
B--無參構造器
--------------
A--有參構造器:b2
B--有參構造器:b2
*/
使用super也可以在成員方法中調用父類的成員方法
public class A {
public void method(){
System.out.println("method:A");
}
}
public class B extends A{
public void method(){
System.out.println("method:B");
super.method();
}
public static void main(String[] args) {
B b1 = new B();
b1.method();
}
}
//運行結果爲:
//A--無參構造器
//B--無參構造器
- 調用當前類構造器用this()方法
this在構造器中可以調用其他的構造器,但必須在第一行且只能調用一次。
public class A {
public A(){
System.out.println("無參構造器");
}
public A(String name){
this();
System.out.println("有參構造器:"+name);
}
public static void main(String[] args) {
A a2 = new A("a2");//有參構造器
}
}
//運行結果爲:
//無參構造器
//有參構造器:a2
另外,this關鍵字也代表當前的實例對象,因此this關鍵字不能用於static方法中。
public void setName(String name) {
this.name = name;
}
- 子類默認調用父類的無參構造器,如果父類自己定義了有參構造器而沒有定義無參構造器,那麼就會報錯。但這時如果子類顯示的調用父類的有參構造器,就不會報錯。
public class A {
public A(String name){
System.out.println("A--有參構造器:"+name);
}
}
public class B extends A{
public B(String name){
super(name);
System.out.println("B--有參構造器:"+name);
}
public static void main(String[] args) {
B b2 = new B("b2");
}
}
//輸出結果爲:
//A--有參構造器:b2
//B--有參構造器:b2
從上例也可以看出先初始化父類的構造器,再初始化子類的構造器。
初始化順序問題
初始化順序:
1. 靜態成員首先被初始化且只初始化一次。
2. 父類構造器被初始化。
3. 實例變量被初始化。
4. 本類構造方法被初始化。
由下述代碼可得上述結論
public class A {
public A(){
System.out.println("A--無參構造器");
}
public A(String name){
System.out.println("A--有參構造器:"+name);
}
}
public class B extends A{
A a2 = new A("a2");
static A a3 = new A();
public B(String name){
super(name);
System.out.println("B--有參構造器:"+name);
}
public static void main(String[] args) {
B b1 = new B("b1");
B b2 = new B("b2");
}
}
//運行結果爲:
/**
A--無參構造器
A--有參構造器:b1
A--有參構造器:a2
B--有參構造器:b1
A--有參構造器:b2
A--有參構造器:a2
B--有參構造器:b2
*/