當創造一個class 時,不希望他可以有多個實例 ,而是希望整個Java的應用中,只使用同一個class ,這時候可以使用單例模式去定義這個class 。
最主要分為兩種實例化 的方式
public class MyHouse {
private static MyHouse instance = new MyHouse();
private static String kitchen = "kitchen";
private MyHouse(){};
public static MyHouse getInstance() {
return instance;
}
public static void cook() {
System.out.println("Use " + kitchen + " to cook");
}
}
餓漢式會在定義類的時候就將它實例化 ,優點是好寫,且在線程 上是安全的,但是相對來說,它也會造成資源的浪費,會在一開始載入類時就先實例化。
public class MyHouse1 {
private static MyHouse1 instance;
private static String kitchen = "kitchen";
private MyHouse1(){};
public static MyHouse1 getInstance() {
if(instance == null) {
instance = new MyHouse1();
}
return instance;
}
public static void cook() {
System.out.println("Use " + kitchen + " to cook");
}
}
懶漢式在定義類的時只會宣告它的變數名 ,當需要使用時才會判斷是否已經實例化 ,優點是不浪費資源,但是在多線程 時上可能會出現問題。
public class MyHouseTest {
public static void main(String[] args) {
// 1
MyHouse house1 = MyHouse.getInstance();
house1.cook(); // Use kitchen to cook
// 2
MyHouse1 house2 = MyHouse1.getInstance();
house2.cook(); // Use kitchen to cook
}
}
MyHouse 在還沒有宣告house1 時(如註解1的位置),MyHouse 其實已經實例化 了,而MyHouse1 則是在宣告了house2 時(如註解2的位置),Java才會先去判斷MyHouse1 是否已經有實例化 ,如果沒有才會去將它實例化。
前面提到的多線程 有可能會有問題則是因為,假設今天同時宣告多個MyHouse1.getInstance(); 時,有可能會造成同時認為尚未實例化 MyHouse1 ,進而將它實例化多次。
💡多線程的內容後面會再提
前面講過一個class 有許多的成員,今天要再來講它的另外一個成員初始化區塊 ,初始化區塊 也只有分成兩種靜態初始化區塊 、實例初始化區塊。
使用的方式:
public class Person {
String name;
static country;
//沒有參數的構造器
Person(){}
// 實例初始化區塊
{
System.out.println("This is Instance Initializer Block");
name = "Tom";
}
// 靜態初始化區塊
static {
System.out.println("This is Static Initializer Block");
country = "Taiwan";
}
}
public class PersonTest {
public static void main(String[] args) {
Person person = new Person();
Person person1 = new Person();
}
}
This is Static Initializer Block
This is Instance Initializer Block
This is Instance Initializer Block
實例初始化區塊 只需要在class 中使用{} 當中的程式碼就會在實例化 這個class 時執行裡面的程式碼,例如上面出現了兩次This is Instance Initializer Block。
靜態初始化區塊 和靜態屬性及靜態方法一樣,它只會在class 載入時執行一次。
實例初始化區塊 :可以使用屬性、方法、靜態屬性、靜態方法。
靜態初始化區塊 :可以使用靜態屬性 、靜態方法。
通常使用初始化區塊 可能會是因為,靜態屬性 中,要賦值時可能要先做一些程式碼的操作再進行賦值,這時候可以使用靜態初始化區塊 ;或者是當構造器中有相同的程式碼時,這時候也可以使用實例初始化區塊 將相同的程式碼放到實例初始化區塊 中(也可以直接使用this 的方式去使用其他構造器)。
💡不要在構造器中對靜態屬性進行任何操作