1. 程式人生 > >Java 構造器初始化

Java 構造器初始化

可以用構造器來進行初始化,但是成員變數的自動初始化是在構造器被呼叫之前發生的,即成員變數的自動初始化不能被阻止

如以下例子:

public class Counter {
	int count;
	Counter(){
		count = 7;
	}
}
count首先是為0,當呼叫其構造方法後,才使得count為7.

1.初始化順序

在類的內部,變數定義的先後順序決定了其初始化順序。但變數的初始化操作會在呼叫任何方法之前完成,包括構造方法,哪怕變數的定義散佈於方法定義之間。

如以下例子:

class Window{
	Window(int i){
		System.out.println("Window("+i+")");
	}
}

class House{
	Window window1 = new Window(1);
	House(){
		System.out.println("----I'm contructor method----");
	}
	Window window2 = new Window(2);
	void f(){
		System.out.println("-----I'm f()-----");
	}
	Window window3 = new Window(3);
}

public class Demo {
	
	public static void main(String[] args) {
		House house = new House();
		house.f();
	}
}
當執行這個程式碼時,其結果為:
Window(1)
Window(2)
Window(3)
----I'm contructor method----
-----I'm f()-----
由此可以看出,Window的幾個物件均在House的構造器和f()方法之前便已完成初始化。

2、靜態資料的初始化
無論建立多少物件,靜態資料都只佔據一份儲存域。static關鍵字不能應用於區域性變數,因此它只能作用於域。

可以通過一個例子來看靜態資料的初始化是如何進行的:

package com.hd.demo;

class Bowl{
	
	Bowl(int i){
		System.out.println("Bowl("+i+")");
	}
	
	void f(int i){
		System.out.println("f("+i+")");
	}
}

class Table{
	static Bowl bolw1 = new Bowl(1);
	Table(){
		System.out.println("----I'm Table contructor method----");
	}
	
	void f(){
		System.out.println("-----I'm f() method in Table-----");
	}
	static Bowl bolw2 = new Bowl(2);
}

class Cupboard{
	Bowl bowl3 = new Bowl(3);
	static Bowl bowl4 = new Bowl(4);
	Cupboard(){
		System.out.println("----I'm Cupboard contructor method----");
		bowl4.f(1);
	}
	void f(){
		System.out.println("-----I'm f() method in Cupboard-----");
	}
	static Bowl bowl5 = new Bowl(5);
}

public class StaticDemo {
	public static void main(String[] args) {
		System.out.println("creating new Cupboard() in main");
		new Cupboard();
		System.out.println("creating new Cupboard() in main");
		new Cupboard();
		table.f();
		cupboard.f();
	}
	static Table table = new Table();
	static Cupboard cupboard = new Cupboard();
}
其執行結果如下:
Bowl(1)
Bowl(2)
----I'm Table contructor method----
Bowl(4)
Bowl(5)
Bowl(3)
----I'm Cupboard contructor method----
f(1)
creating new Cupboard() in main
Bowl(3)
----I'm Cupboard contructor method----
f(1)
creating new Cupboard() in main
Bowl(3)
----I'm Cupboard contructor method----
f(1)
-----I'm f() method in Table-----
-----I'm f() method in Cupboard-----
以上程式碼有幾個需要注意的地方,一個是StaticDemo中在main方法的下面定義了靜態資料成員table和cupboard。它們會在main方法執行之前先進行初始化。另一個是Cupboard類中,先定義了一個非靜態的bowl3成員。最後就是在main方法中又new了Cupboard物件。

通過以上執行結果可以得出以下結果:

1)、靜態初始化只有在必要的時候才會進行,如果不建立Table物件,那麼bowl1和bowl2就不會建立。

2)、靜態資料只有在第一次被訪問時才會進行初始化,此後便不再被初始化。比如,在main方法中new Cupboard,初始化了非靜態成員bowl3,而靜態成員bowl4和bowl5不再被初始化。

3)、初始化的順序是先靜態物件,後是非靜態物件。

3、顯示的靜態初始化

先看一段程式碼:

class Cup{
	Cup(int mark){
		System.out.println("Cup("+mark+")");
	}
	
	void f(int mark){
		System.out.println("f("+mark+")");
	}
}

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



public class ExplicitStatic {
	public static void main(String[] args) {
		Cups.cup1.f(1);	  //(1)
	}
	//static Cups cups1 = new Cups();  //(2)
	//static Cups cups2 = new Cups();  //(3)
}
其執行結果如下:
Cup(1)
Cup(2)
f(1)
假設註釋掉(1)的程式碼,解除(2)或(3)的程式碼,那麼結果就會為:
Cup(1)
Cup(2)
如果同時解除(2)和(3)的程式碼,其執行結果都是一樣的。因為上面已經提到,靜態資料只有在第一次被訪問時才會初始化,此後便不再初始化。

4、非靜態例項初始化

先看一段程式碼:

class Mug{
	Mug(int i){
		System.out.println("Mug("+i+")");
	}
	
}

public class Mugs {
	Mug mug1;
	Mug mug2;
	{
		mug1 = new Mug(1);
		mug2 = new Mug(2);
	}
	
	Mugs(){
		System.out.println("無參構造器");
	}
	Mugs(int i){
		System.out.println("有參構造器");
	}
	
	public static void main(String[] args) {
		new Mugs();
		new Mugs(1);
	}
}
執行結果:
Mug(1)
Mug(2)
無參構造器
Mug(1)
Mug(2)
有參構造器
可以看到,因為少了一個static關鍵字,因此,每new一個物件,mug1和mug2都會初始化一次,並且也是在構造器執行之前完成。

寫這篇部落格是因為在《Java思想程式設計》中看到專門講構造器初始化的知識,感覺自己有很多不懂的地方,看了兩三遍才明白。現在再總結一下,算是加深印象吧。