初始化 Java 數據字段(學習 Java 編程語言 033)

初始化數據字段的方法:java

  1. 在構造器中設置值。
  2. 在聲明中賦值。
  3. 使用初始化塊(initialization block)賦值。

1. 默認字段初始化

若是在構造器中沒有顯示地爲字段設置初值,那麼就會被自動地賦爲默認值:數值爲 0、布爾值爲 false、對象引用爲 null。有些人認爲依賴默認值的作法是一種很差的編程實踐。確實,若是不明確地對字段進行初始化,就會影響程序代碼的可讀性。編程

註釋: 這是字段與局部變量的一個重要區別。方法中的局部變量必須明確初始化。可是在類中,若是沒有初始化類中的字段,將會自動初始化爲默認值(0、 false 或 null);dom

public class Employee {
    private String name;
    private double salary;
    protected LocalDate hireDay;

    public Employee() {}
    ...
    public String getName() {
        return name;
    }
    public double getSalary() {
        return salary;
    }
    public LocalDate getHireDay() {
        return hireDay;
    }
}

若是沒有在構造器中指定如何初始化某些字段,默認狀況下,將會將 slary 字段初始化爲 0,將 name 和 hireDay 字段初始化爲 null。
可是,這並非一個好主意。若是此時調用 getName 方法或 getHireDay 方法,就會獲得一個 null 引用。這應該不是咱們但願的結果:
LocalDate h = harry.getHiredDay();
int year = h.getYear(); // throws exception if h is nullide

2. 在構造器中設置值

先看看 Employee 類的構造器:this

public class Employee {
    private String name;
    private double salary;
    private LocalDate hireDay;

    public Employee(String name, double salary, int year, int month, int day) {
        this.name = name;
        this.salary = salary;
        hireDay = LocalDate.of(year, month, day);
    }
    ...
}

構造器與類同名。在構造 Employee 類的對象時,構造器會運行,從而將實例字段初始化爲所但願的初始狀態。code

當使用下面這條代碼建立 Employee 類的實例時:
new Employee("James Bond", 100000, 1950, 1, 1);
將會把實例字段設置爲:orm

name = "James Bond";
salary = 100000;
hireDay = LocalDate.of(1950, 1, 1); // 1950-01-01

3. 在聲明中賦值

能夠在類定義中直接爲任意字段賦值:對象

public class Employee {
    private String name = "";
}

在執行構造器以前先完成這個賦值操做。若是一個類的全部構造器都但願把某個特定的實例字段設置爲同一個值,這個語法特別有用。get

初始值不必定是常量值。在下面的例子中,就是利用方法調用初始化一個字段。考慮如下 Employee 類,其中每一個員工有一個 id 字段。能夠使用下列方式進行初始化:generator

public class Employee {
    private static int nextId;
    private int id = assignId();
    ...
    private static int assignId() {
        int r = nextId;
        nextId++;
        return r;
    }
    ...
}

4. 初始化塊

在一個類的聲明中,能夠包含任意多個代碼塊。只要構造這個類的對象,這些塊就會被執行。

class Employee {
    private static int nextId;

    private int id;
    private String name;
    private double salary;

    // 初始化塊
    {
        id = nextId;
        nextId++;
    }

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }
    ...
}

不管使用哪一個構造器構造對象,id 字段都會在對象初始化塊中初始化。首先運行初始化塊,而後才運行構造器的主體部分。

這種機制不是必需的,也不常見。一般會直接將初始化代碼放在構造器中。

註釋: 能夠在初始化塊中設置字段,即便這些字段在類後面才定義,這是合法的。可是,爲了不循環定義,不容許讀取在後面初始化的字段。這些規則太過複雜,讓編譯器的實現者都很頭疼,因此較早的 Java 版本中這些規則的實現存在一些小錯誤,所以建議老是將初始化塊放在字段定義以後。

能夠經過提供一個初始化值,或者使用一個靜態的初始化塊來初始化對靜態字段。前面已經介紹過第一種機制:
private static int nextId = 1;
若是類的靜態字段須要很複雜的初始代碼,那麼能夠使用靜態的初始化塊。將代碼放在一個塊中,並標記關鍵字 static。下面的示例中,其功能是將員工 ID 的起始值賦予一個小於 10 000 的隨機數:

class Employee {
    private static int nextId;
    // 靜態的初始化塊(static initialization block)
    static
    {
        Random generator = new Random();
        nextId = generator.nextInt(1000);

    }
}

在類第一次加載的時候,將會進行靜態字段的初始化。與實例字段同樣,除非將靜態字段顯式地設置成其餘值,不然默認的初始值是 0、false 或 null。全部的靜態字段初始化方法以及靜態初始化塊都將依照類聲明中出現的順序執行。

import java.util.Random;

public class ConstructorTest {

    public static void main(String[] args) {
        var staff = new Employee[3];
        staff[0] = new Employee("Harry", 4000);
        staff[1] = new Employee(6000);
        staff[2] = new Employee();

        for(Employee employee : staff) {
            System.out.println(employee);
        }
    }
}
class Employee {
    private static int nextId;

    private int id;
    private String name = "";
    private double salary;

    static
    {
        Random generator = new Random();
        // 設置 nextId 爲 0 到 9999 的隨機數
        nextId = generator.nextInt(10000);
    }

    // 初始化塊
    {
        id = nextId;
        nextId++;
    }

    public Employee(String name, double salary) {
        this.name = name;
        this.salary = salary;
    }

    public Employee(double salary) {
        this.salary = salary;
    }

    public Employee() {

    }
    /**
     * 增長工資
     * @param byPercent 百分比
     */
    public void raiseSalary(double byPercent) {
        double raise = salary * byPercent / 100;
        salary += raise;
    }
    public String getName() {
        return name;
    }

    public double getSalary() {
        return salary;
    }

    public int getId() {
        return id;
    }

    public String toString() {
        String str = "%s[name=%s,id=%d,salary=%s]";
        return String.format(str, getClass(), name, id, salary);
    }
}
相關文章
相關標籤/搜索