建構函式在建立物件時用來初始化物件。 它與類具有相同的名稱,並且在語法上與方法類似。但是,建構函式沒有返回值型別。
通常,使用建構函式為類定義的範例變數提供初始值,或執行建立完全形成的物件所需的其他啟動過程。
所有類都有建構函式,無論是否定義了建構函式,因為Java會自動提供一個預設建構函式,將所有成員變數初始化為零。 但是,一旦定義了自己的建構函式,就不再使用預設建構函式。
語法
以下是建構函式的語法 -
class ClassName {
ClassName() {
}
}
每當使用new
關鍵字建立類的範例時,都會呼叫建構函式並返回類的物件。 由於建構函式只能將物件返回給類,它是由java執行時隱式完成的,不應該向它新增返回型別。
如果將返回型別新增到建構函式,那麼它將成為類的方法。 這是java執行時區分普通方法和建構函式的方式。 假設在Employee
類中有以下程式碼。
import java.io.*;
public class Employee {
public Employee() {
System.out.println("Employee建構函式");
}
public Employee Employee() {
System.out.println("Employee一般方法");
return new Employee();
}
}
這裡第一個是建構函式,因為它沒有返回型別和返回語句。 第二個是一個常規方法,我們再次呼叫第一個建構函式來獲取Employee
範例並返回它。建議不要將方法名稱與類名相同,因為會容易造成混淆。
java中有三種型別的建構函式。
下面將通過範例程式來學習這些建構函式型別。
不需要始終在類程式碼中提供建構函式實現。如果不提供建構函式,那麼java提供預設的建構函式實現供我們使用。 下面來看一個使用預設建構函式的簡單程式,它沒有顯式定義建構函式。
package com.yiibai.constructor;
public class Car {
public static void main(String[] args) {
Car c = new Car();
}
}
getter
/setter
方法存取和初始化其他屬性。沒有任何引數的建構函式稱為無參建構函式。 這就像覆蓋預設建構函式並用於執行一些預初始化的東西,例如:檢查資源,網路連線,紀錄檔記錄等。通過以下程式碼瀏覽一下java中的無參建構函式。
package com.yiibai.constructor;
public class Car {
// 無參建構函式
public Car() {
System.out.println("No-Args Constructor");
}
public static void main(String[] args) {
Car d = new Car();
}
}
當呼叫new new()
時,將呼叫無參建構函式。執行上面程式碼,程式在控制台輸出結果如下:
No-Args Constructor
帶引數的建構函式稱為引數化建構函式。下面來看看java中引數化建構函式的例子。
package com.yiibai.constructor;
public class Language {
private String name;
public Language(String n) {
System.out.println("Parameterized Constructor");
this.name = n;
}
public String getName() {
return name;
}
public static void main(String[] args) {
Language lang = new Language("Java");
System.out.println(lang.getName());
}
}
執行上面程式碼,程式在控制台輸出結果如下:
Parameterized Constructor
Java
當有多個建構函式時,它就是java中的建構函式過載。通過下面範例程式碼來了解java程式中建構函式過載。
package com.yiibai.constructor;
public class Data {
private String name;
private int id;
//no-args constructor
public Data() {
this.name = "Default Name";
}
//one parameter constructor
public Data(String n) {
this.name = n;
}
//two parameter constructor
public Data(String n, int i) {
this.name = n;
this.id = i;
}
public String getName() {
return name;
}
public int getId() {
return id;
}
@Override
public String toString() {
return "ID="+id+", Name="+name;
}
public static void main(String[] args) {
Data d = new Data();
System.out.println(d);
d = new Data("Java");
System.out.println(d);
d = new Data("Maxsu", 25);
System.out.println(d);
}
}
不能將abstract
,final
,static
和synchronized
關鍵字與建構函式一起使用。 但是,可以使用存取修飾符來控制類物件的範例化。 使用public
存取和default
存取仍然沒有問題,但是將建構函式設為私有的用途是什麼? 在這種情況下,任何其他類都將無法建立該類的範例。
如果想要實現單例設計模式,建構函式是private
。 由於java自動提供預設建構函式,因此必須顯式建立建構函式並將其保持為private
。 用戶端類提供了實用程式靜態方法來獲取類的範例。 下面給出了Data
類的私有建構函式的範例。
// private 建構函式
private Data() {
// 單例模式實現的空建構函式
// 可以在類的getInstance()方法中使用程式碼
}
當建構函式呼叫同一個類的另一個建構函式時,它被稱為建構函式連結。需要使用this
關鍵字來呼叫該類的另一個建構函式。有時它用於設定類變數的一些預設值。
請注意,另一個建構函式呼叫應該是程式碼塊中的第一個語句。 此外,不應該有一個會產生無限迴圈的遞迴呼叫。下面來看看java程式中建構函式連結的一個例子。
package com.yiibai.constructor;
public class Employee {
private int id;
private String name;
public Employee() {
this("Maxsu", 1999);
System.out.println("Default Employee Created");
}
public Employee(int i) {
this("Maxsu", i);
System.out.println("Employee Created with Default Name");
}
public Employee(String s, int i) {
this.id = i;
this.name = s;
System.out.println("Employee Created");
}
public static void main(String[] args) {
Employee emp = new Employee();
System.out.println(emp);
Employee emp1 = new Employee(10);
System.out.println(emp1);
Employee emp2 = new Employee("Yiibai", 20);
System.out.println(emp2);
}
@Override
public String toString() {
return "ID = "+id+", Name = "+name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
上程式碼程式碼中,已經重寫了toString()
方法來列印一些有關Employee
物件的資訊。 以下是上面程式產生的輸出 -
Employee Created
Default Employee Created
ID = 1999, Name = Maxsu
Employee Created
Employee Created with Default Name
ID = 10, Name = Maxsu
Employee Created
ID = 20, Name = Yiibai
從另一個建構函式呼叫一個建構函式,這個建構函式被稱為建構函式連結過程。
有時一個類是從超類繼承的,在這種情況下,如果必須呼叫超類建構函式,那麼可以使用super
關鍵字。
請注意,super
造函式呼叫應該是子類建構函式中的第一個語句。 此外,在範例化子類建構函式時,java首先初始化超類,然後初始化子類。 因此,如果未顯式呼叫超類建構函式,則java執行時將呼叫default
或no-args
建構函式。下面將通過一些範例程式來理解這些概念。
假設有兩個類,如下所示。
Person
類原始碼 -
package com.yiibai.constructor;
public class Person {
private int age;
public Person() {
System.out.println("Person Created");
}
public Person(int i) {
this.age = i;
System.out.println("Person Created with Age = " + i);
}
}
Student
類原始碼 -
package com.yiibai.constructor;
public class Student extends Person {
private String name;
public Student() {
System.out.println("Student Created");
}
public Student(int i, String n) {
super(i); // 超類建構函式呼叫
this.name = n;
System.out.println("Student Created with name = " + n);
}
}
現在,如果建立一個Student
物件,如下所示:
Student st = new Student();
那將輸出什麼結果? 上面程式碼的輸出將是:
Person Created
Student Created
所以呼叫轉到了Student
類的no-args
建構函式,因為在第一個語句中沒有super
呼叫,所以呼叫了Person
類的no-args
或預設建構函式。如果使用Student
類的引數化建構函式作為 -
Student st = new Student(1999,"Maxsu");
那麼輸出將是:
Person Created with Age = 1999
Student Created with name = Maxsu
這裡輸出很明顯,因為我們顯式呼叫了超類建構函式,所以java不需要從no-args
建構函式這邊做任何額外的工作。
Java拷貝建構函式將相同類的物件作為引數,並建立它的副本。有時需要另一個物件的副本來進行一些處理。 可以通過以下方式做到這一點:
現在來看看如何編寫複製建構函式,假設有一個類:Fruits
,程式碼如下。
package com.yiibai.constructor;
import java.util.ArrayList;
import java.util.List;
public class Fruits {
private List<String> fruitsList;
public List<String> getFruitsList() {
return fruitsList;
}
public void setFruitsList(List<String> fruitsList) {
this.fruitsList = fruitsList;
}
public Fruits(List<String> fl) {
this.fruitsList = fl;
}
public Fruits(Fruits fr) {
List<String> fl = new ArrayList<>();
for (String f : fr.getFruitsList()) {
fl.add(f);
}
this.fruitsList = fl;
}
}
請注意,Fruits(Fruits fr)
執行深拷貝以返回物件的副本。下面通過一個測試程式,了解為什麼拷貝建構函式比拷貝物件更好。
package com.yiibai.constructor;
import java.util.ArrayList;
import java.util.List;
public class ConstructorTest {
public static void main(String[] args) {
List<String> fl = new ArrayList<>();
fl.add("Mango");
fl.add("Orange");
Fruits fr = new Fruits(fl);
System.out.println(fr.getFruitsList());
Fruits fr = fr;
fr.getFruitsList().add("Apple");
System.out.println(fr.getFruitsList());
fr = new Fruits(fr);
fr.getFruitsList().add("Banana");
System.out.println(fr.getFruitsList());
System.out.println(fr.getFruitsList());
}
}
執行上面查詢語句,得到以下結果:
[Mango, Orange]
[Mango, Orange, Apple]
[Mango, Orange, Apple]
[Mango, Orange, Apple, Banana]
請注意,當使用複製建構函式時,原始物件和它的副本彼此無關,並且其中一個中的任何修改都不會反映到其他物件中。