當創造一個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
的方式去使用其他構造器)。
💡不要在構造器中對靜態屬性
進行任何操作