一文了解 Java 中的構造器

2022-09-14 18:06:17
摘要:Java 也採用了構造器,並且還提供了一個垃圾收集器(garbage collector),當不再使用記憶體資源的時候,垃圾收集器會自動將其釋放。

本文分享自華為雲社群《一文帶你瞭解 Java 中的構造器》,作者: 宇宙之一粟 。

C ++ 引入了構造器(constructor,也叫建構函式)的概念,它是在建立物件時被自動呼叫的特殊方法

Java 也採用了構造器,並且還提供了一個垃圾收集器(garbage collector),當不再使用記憶體資源的時候,垃圾收集器會自動將其釋放。

構造器定義

在 Java 中,可以通過編寫構造器來確保每個物件的初始化。但是這裡有兩個問題:

  1. 這個構造器使用的任何名字都有可能與類裡某個成員相沖突;
  2. 編譯器負責呼叫構造器,所以它必須始終知道應該呼叫哪個方法。

C++ 語言採用的方案就是將構造器和類的名字定義相同,Java 也採用了這個方案。

構造器的作用是用來建立一個新的類的範例,當一個物件被建立時,JVM 使用一個建構函式,併為其分配記憶體空間。

語法結構

class ClassName {
 ClassName() {
 }
}

例如,在下面的範例中,我們建立了一個名為 ReLearnConstructor 的建構函式。在建構函式內部,我們正在初始化 hello 變數的值。:

public class ReLearnConstructor {

String hello; // 屬性
 // 構造器
public ReLearnConstructor() {
hello = "Hello, Constructor!";
}

public static void main(String[] args) {

ReLearnConstructor rc = new ReLearnConstructor();
System.out.println(rc.hello);
}
}

注意建立 ReLearnConstructor 類的物件的語句:ReLearnConstructor rc = new ReLearnConstructor();

在這裡,當建立物件時,呼叫 ReLearnConstructor 建構函式。並且,hello 變數的值被初始化。

因此列印的 hello 的值為:

構造器目的

建構函式的目的是初始化物件的狀態,為所有宣告的屬性賦值。如果我們沒有自定義建構函式,JVM 就會為這些屬性分配預設值。

原始型別的預設值:

  • 整數型別是 0
  • 浮點型別是 0.0
  • 布林型別是 false

對於其他 Java 參照型別,預設值是null,這意味著參照型別的屬性沒有被分配任何值。

後面可以用程式碼檢視這些預設值。

構造器分類

在 Java 中,有三種型別的構造器:

  1. 無參構造器
  2. 有參構造器
  3. 預設構造器

無參構造器

與方法類似,Java 建構函式可能有引數,也可能沒有任何引數。如果建構函式不接受任何引數,則稱為無引數構造器。例如上述程式碼中 ReLearnConstructor 構造器就是:

// 無參構造器
public ReLearnConstructor() {
hello = "Hello, Constructor!";
}

有參構造器

字面理解,具有引數的建構函式稱為有引數構造器。那為什麼需要使用有參構造器?

有參構造器可用於為不同物件提供不同初始化的值。 例如:

public class ReLearnConstructor {

String languages;

// 接受單個引數的構造器
public ReLearnConstructor(String lang) {
languages = lang;
System.out.println("我在學習 " + languages + " 語言!");
}

public static void main(String[] args) {
// 向構造器中傳入不同的值
ReLearnConstructor rc1 = new ReLearnConstructor("Java");
ReLearnConstructor rc2 = new ReLearnConstructor("Go");
ReLearnConstructor rc3 = new ReLearnConstructor("Python");
}
}

執行結果:

預設構造器

如果我們不建立任何建構函式,Java 編譯器會在程式執行期間自動建立一個無引數建構函式。這個建構函式稱為預設建構函式。來看一個例子;

public class ReLearnConstructor {

String languages;
int a;
boolean b;
float c;
public static void main(String[] args) {
ReLearnConstructor rc = new ReLearnConstructor();
System.out.println("預設值:");
System.out.println("languages:" + rc.languages);
System.out.println("a:" + rc.a);
System.out.println("b:" + rc.b);
System.out.println("c:" + rc.c);
}
}

執行結果:

預設值:
languages:null
a:0
b:false
c:0.0

可以看到,我們還沒有建立任何建構函式。因此,Java 編譯器會自動建立預設建構函式。上述表格得以印證。

原生方法和構造器的區別

  • 建構函式必須與在 Java 中定義的類具有相同的名稱
  • 當方法沒有返回任何值時,建構函式不會返回任何型別,而方法則具有返回型別或 void
  • 在物件建立時,僅呼叫建構函式一次,而方法可以被呼叫任何次數

如果我們不用構造器來給屬性賦值的話,可以先使用 new 運運算元獲取類的範例,並使用類的 setter 方法設定值,如下:

import java.util.Arrays;
class Person
{
 private String name;
 private int age;
    @Override
 public String toString() {
 return Arrays.asList(name, String.valueOf(age)).toString();
 }
 public void setName(String name) {
 this.name = name;
 }
 public void setAge(int age) {
 this.age = age;
 }
 // getters
}
// Initialize an object in Java
class Main
{
 public static void main(String[] args)
 {
        Person person = new Person();
 person.setName("Yuzhou1su");
 person.setAge(22);
 System.out.println(person);
 }
}

通過構造器進行初始化就可以省去我們的 setter 方法。

如下的例子:

import java.util.Arrays;
class Person {
 private String name;
 private int age;
 // 構造器
 public Person(String name, int age) {
 this.name = name;
 this.age = age;
 }
 public String toString() {
 return Arrays.asList(name, String.valueOf(age)).toString();
 }
}
class SimpleConstructor {
 public static void main(String[] args) {
        Person person = new Person("Yuzhou1su", 22);
 System.out.println(person);
 }
}

執行結果:

[Yuzhou1su, 22]

構造器過載

與 Java 方法過載類似,我們也可以建立兩個或多個具有不同引數的建構函式。這稱為建構函式過載。

public class ReLearnConstructor {

String language;

public ReLearnConstructor() {
this.language = "Java";
}

// 構造器
public ReLearnConstructor(String language) {
this.language = language;
}

public void getName() {
System.out.println("程式語言:" + this.language);
}

public static void main(String[] args) {
ReLearnConstructor rc1 = new ReLearnConstructor();

ReLearnConstructor rc2 = new ReLearnConstructor("Python");

rc1.getName();
rc2.getName();
}
}

在上面的例子中,我們有兩個建構函式:ReLearnConstructor() 和 ReLearnConstructor(String language)。在這裡,兩個建構函式都用不同的值初始化變數語言的值。根據建立物件時傳遞的引數,呼叫不同的建構函式,分配不同的值。

執行結果:

程式語言:Java
程式語言:Python

拷貝構造器

Java 中的拷貝構造方法是一種使用該類的一個物件構造另外一個物件的構造方法。

複製建構函式是一種特殊建構函式,用於將新物件建立為現有物件的副本。它只需要一個引數,它將是同一類的另一個範例。我們可以使用 this() 語句從複製建構函式中顯式呼叫另一個建構函式:

public class ReLearnConstructor {

private String language;

// 構造器
public ReLearnConstructor(String language) {
this.language = language;
}

// 拷貝構造器
public ReLearnConstructor(ReLearnConstructor rc) {
this.language = rc.language;
}

public void getName() {
System.out.println("程式語言:" + this.language);
}

public static void main(String[] args) {
ReLearnConstructor rc = new ReLearnConstructor("Python");

ReLearnConstructor copyOfrc = new ReLearnConstructor(rc);

rc.getName();
copyOfrc.getName();
}
}

執行結果:

程式語言:Python
程式語言:Python

當需要拷貝一個帶有多個成員變數的複雜物件或者想構造已存在物件的深拷貝物件時非常有用。

匿名內部類

除了上文介紹的使用構造器的方法,另一種初始化物件的方法是使用「雙大括號初始化」。這將建立一個匿名內部類,其中只有一個範例初始化程式。建議不要使用這種方法。

import java.util.Arrays;
class Person
{
 private String name;
 private int age;
    @Override
 public String toString() {
 return Arrays.asList(name, String.valueOf(age)).toString();
 }
 public void setName(String name) {
 this.name = name;
 }
 public void setAge(int age) {
 this.age = age;
 }
 // getters
}
// Initialize an object in Java
class Main
{
 public static void main(String[] args)
 {
 // Anonymous class
        Person person = new Person() {{
 // Initializer block
 setName("Yuzhou1su");
 setAge(22);
 }};
 System.out.println(person);
 }
}

總結

  • 範例化物件時會隱式呼叫建構函式。
  • 建立建構函式的兩條規則是:建構函式的名稱應與類相同。Java 建構函式不能有返回型別。
  • 如果一個類沒有建構函式,Java 編譯器會在執行時自動建立一個預設建構函式。預設建構函式使用預設值初始化範例變數。例如 int 變數將被初始化為 0
  • 建構函式型別:
  • 無參構造器 - 不接受任何引數的建構函式引數化建構函式
  • 接受引數的構造器 - 接受引數的建構函式
  • 預設構造器 - 如果沒有明確定義,Java 編譯器會自動建立一個建構函式。
  • 建構函式不能被 abstract、static 或 final 修飾

編譯器會報如下錯誤:

Illegal modifier for the constructor in type ReLearnConstructor; only public, protected & private are permitted
  • 建構函式可以過載但不能被覆蓋

 

點選關注,第一時間瞭解華為雲新鮮技術~