定義一個空接口:
// Null interface, do nothing but you'll see the usage later
public interface IAntiSingleton {
}
定義一個通用的單例模式
public class AntiSingleton implements IAntiSingleton {
private static final AntiSingleton instance = new AntiSingleton();
public static AntiSingleton getInstance() {
return instance;
}
}
繼承一個classloader並生成AntiSingleton對象
public class NewClassLoader extends ClassLoader {
public IAntiSingleton createNewOne() throws Exception {
InputStream is = getClass().getResourceAsStream("AntiSingleton.class");
byte[] b = new byte[is.available()];
is.read(b);
Class clz = defineClass(null, b, 0, b.length);
Object o = clz.newInstance();
return (IAntiSingleton) o;
}
}
測試方法:
public class TestAntiSingleton {
public static void main(String[] args) throws Exception {
AntiSingleton instance = AntiSingleton.getInstance();
NewClassLoader loader = new NewClassLoader();
IAntiSingleton newObj = loader.createNewOne();
System.out.println(AntiSingleton.getInstance() == newObj);
}
}
output:
=========
false
[b]總結:[/b]
java中,一個類可以有多個定義,並且這些類名可以相同(但同一個類加載器產生類的類名不能相同)。如果不同類加載器兩個類名相同,即使類的定義相同,甚至一個類的定義是由另一個類產生的,這兩個類也是不同的類。
這也就是輸出結果產生false的原因,因爲此時兩個類雖然名字相同,但是其實已經不是一個類。此時的單例模式,看起來是失效的。注意上面爲什麼要用接口,因爲此時在程序中直接使用NewClassLoader用AntiSingleton對輸出結果進行轉型,在運行時就會拋出一個類型轉換Exception。
可以想到的一種情況是,tomcat中,可以部署很多項目,各個項目中是可以出現相同的類名的,這就需要不同的classloader分別load生成這些類。
此外,GoF計劃對“設計模式”進行修訂,其中提到了要剔除“單例模式”,很期待修訂版早點出來。