【Java】初始化

默認域初始化

  1. 若是在構造器中沒有顯示地給域賦予初值,那麼就會被自動賦予默認值:數值爲0,布爾值爲false,對象引用爲null。

無參數構造器

不少類都包含一個無參數的構造函數,對象由無參數構造函數建立時,其狀態會設置爲適當的默認值。例如,以下是Employee的無參數構造函數:java

pubilc Employee() {
    name = "";
    salary = 0;
    hireDay = new Date();
}
  1. 若是編寫一個類時沒有編寫構造器, 那麼系統就會提供一個無參數的構造器。這個構造器將全部的實例域設置爲默認值。因而,實例域中的數值型數據設置爲0、布爾型數據設置爲false,全部對象引用將設置爲null。
  2. 若是類中至少提供了一個構造器,可是沒有提供無參數的構造器,則在構造對象若是沒有提供參數就會被視爲不合法。

顯示域初始化(指定初始化)

因爲類的構造器方法能夠重載,因此能夠採用多種形式設置類的實例域的初始狀態。確保無論怎麼調用構造器,每一個實例域均可以被設置爲一個有意義的數初值。這是一種很好的設計習慣。
能夠在類的定義中,直接將一個值付給任何域。例如:數組

class A{}
Class Employee {
    private String name = "";
    private A a = new A();
}

在執行構造器以前先執行賦值操做。當一個類的全部構造器都但願把相同的值賦給某個特定的實例域時,這種方式特別有用。
初始值不必定是常量。在下面這個例子中,能夠調用方法對域進行初始化。Employee類中每一個僱員都有一個id域。可使用下列方式進行初始化:app

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

這個方法也可帶有參數,但這些參數必須是已經初始化的了。所以,能夠這樣寫:ide

public class MethodInit {
    int i = f();
    int j = g(i);
    int f() {return 11;}
    int g(int n ) {return n* 10;}

但像下面這樣就不對了:函數

public class MethodInit{
    int j = g(i); //Illegal forward reference
    int i = f();
    int f() {return 11;}
    int g(int n) {return n * 1

初始化塊

前面已經講過兩種初始化數據域的方法:this

  • 在構造器中設置值
  • 在聲明中初始化
    實際上,Java中還有第三種機制,稱爲初始化塊。在一個類的生命中,能夠包含多個代碼塊。只要構造類的對象,這些塊就會被執行。例如:
class Employee{
    private static int nextId;
    
    private int id;
    private String name;
    private double salary;

    //object initialization block
    {
        id = nextId;
        nextId++;
    }

    public Employee(String n, dobule s) {
        name = n;
        salary = s;
    }
    
    public Employee(){
        name = "";
        salary = 0;
    }
}

在這個示例中,不管使用哪一個構造器構造對象,id域都在對象初始化塊中被初始化。首先運行初始化塊,而後才運行構造器的主體部分。設計

this關鍵詞

假設你但願在方法的內部得到對當前對象的引用,就可使用this關鍵字。this關鍵字只能在方法的內部使用,表示對「調用這個方法的那個對象」的引用。this的用法和其餘對應引用並沒有不一樣。只要注意,若是在方法內部調用同一個類的另外一個方法,就沒必要使用this,直接調用便可。code

只有當須要明確指出對當前對象的引用時,才須要使用this關鍵字。例如,當須要返回對當前對象的引用時,就經常須要在return語句裏這樣寫:對象

public class Leaf{
    int i = 0;
    Leaf increment() {
        i++:
        return this;
    }
}

public static void main(String[] args) {
    Leaf  x = new Leaf();
    x.increment().increment().increment();
}

因爲increment()經過this關鍵字返回了對當前對象的引用,因此很容易在一條語句中對同一個對象進行屢次操做。
this關鍵字對於將對於將當前對象傳遞給其餘對象也頗有用:ci

Class Person{
    public void eat(Apple apple) {
        Apple peeled = apple.getPeeled();
        System.out.println("Yummy");
   }
}

class Peeler {
    static Apple peel(Apple apple) {
        //... remove peel
        return apple; //Peeled
    }
}

class Apple{
    Apple getPeeled() {return Peeler.peel(this);}
}

public class PassingThis {
    public static void main(Strings[] args) {
        new Person.eat(new Apple));
    }
}
參數名

構造器的的參數名和引用以下所示:

Class Employee{
    private String name;
    private double salary;

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

它基於這樣一個事實:參數變量用一樣的名字將實例域屏蔽起來。例如,若是將參數命名爲salary,salary將引用這個參數,而不是實例域。可是,能夠採用this的形式訪問實例域。

調用另外一個構造器

若是構造器的第一個句子形如(this...),這個構造器將調用同一個類的另外一個構造器。下面是一個典型的例子:

public Employee() {
    //calls Employee(String, double)
    this("Employee #" + nextId, s);
    nextId++;
}

儘管能夠用this調用另外一個構造器,但卻不能同時調用兩個。此外,必須將構造器調用置於方法最起始處,不然編譯器會報警。
***

靜態域初始化

  1. 若是一個域是靜態的基本類型域,且沒有對它進行初始化,那麼它就會得到基本類型的標準初值;若是它是一個對象引用,那麼它的默認初始值就是null。
  2. 若是想在定義處進行初始化,採起的方法與非靜態數據沒什麼不一樣
Class A{
    private static B b = new B();
}

3.也能夠用使用指定初始化,不過要在初始化塊的外面加 static關鍵字

class Cup{
    Cup(int marker) {
    }
}

class Cups{
    static Cup cup1;
    static Cup cup2;
    static {
        cup1 = new Cup(1);
        cup2 = new Cup(2);
    }
    Cup() {
        print("Cups()");
    }
}

public class ExplicitStatic {
    public static void main(Strings[] args) {
        print("Inside main()");
        Cups.cup1.f(99);
    }
    static Cups cups1 = new Cups();
    static Cups cups2 = new Cups();
}

不管是經過標爲(1)的那行代碼訪問靜態的cup1對象,仍是把標爲(1)的行註釋掉,讓它去運行標爲(2)的那行代碼(即解除標爲(2)的行的註釋),Cups的靜態初始化動做都會獲得執行。若是把標爲(1)和(2)的行同時註釋掉,Cups的靜態初始化動做就不會進行。此外,激活一行仍是兩行標爲(2)的代碼(即解除註釋)都可有可無,靜態初始化動做只進行一次。

數組初始化

數組初始化主要有兩種形式。第一種以下:

//Aggregate initialization
BerylliumSphere[] d = { new BerylliumSphere(), new BerylliumSphere(), new BerylliumSphere()};

數組d代表使用"彙集初始化"語法建立數組對象,而且以BerylliumSphere對象將其初始化的過程,可是這個操做必須在定義d的位置使用。

第二種以下:

//Dynamic aggregate initialization
a = new BerylliumSphere[] { 
new BerylliumSphere(), new BerylliumSphere()
};

這種方法被看做是"動態的彙集初始化",這種方法能夠在任意位置建立和初始化數組對象。例如,假設方法hide()須要一個BerylliumSpere對象的數組做爲輸入參數。能夠以下調用:
hide(d);
但也能夠動態地建立將要做爲參數傳遞的數組:

hide(new BerylliumSpere[]{new BerylliumSpere()}

雙括號初始化(Java核心技術卷一,P243)

雙括號初始化利用了內部類的語法。假設想構造一個數組列表,並將它傳遞到一個方法。

ArrayList<String> friends = new ArrayList<>();
friends.add("Harrys");
friends.add("Tony");
invite(friends);

若是不須要這個數組列表,最好讓它做爲一個匿名列表。不過做爲一個匿名列表,添加元素方法以下:

invite(new ArrayList<String>(){{add("Harrys");add(""Tony"")}})

注意這裏的雙括號。外括號創建了Arraylist的一個匿名子類。內括號則是一個對象構造塊。

相關文章
相關標籤/搜索