2010년 5월 31일 월요일

なんとなく気になったので、Singleton を破壊するための TIPS

http://d.hatena.ne.jp/SiroKuro/20080403/1207236878

 

なんとなく気になったので、Singleton を破壊するための TIPS を余談として提示してみます。

結局クラスが一意であることを利用してクラスを1対1に結びついた単一のオブジェクトを作ってるだけなんだから

証明を書くには余白が足りない - 西尾泰和のはてなダイアリー

結局、クラスが一意じゃなければ、Singleton は破壊できちゃうんですよね。

今回破壊する Singleton はこういうクラスです。いたってシンプル

public class Singleton {
    private static final Singleton instance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() { return instance; }
}

これを、こういうコードからロードしてみちゃったりします。だいぶ乱暴なことをしますね。

import java.io.*;
class test {
    public static void main(String[] args) throws Exception {
        System.out.println(newInstance() == newInstance());
    }
    private static Object newInstance() throws Exception {
        File file = new File("Singleton.class");
        final byte[] data = new byte[(int)file.length()];
        new FileInputStream(file).read(data, 0, data.length);
        return new ClassLoader() {
            public Class<?> destroySingleton() {
                return defineClass("Singleton", data, 0, data.length);
            }
        }.destroySingleton().getMethod("getInstance").invoke(null);
    }
}

結果は "false"

defineClass のたびに、新しい Singleton クラスが返ってきます。

素人にはお勧めできない。

微妙にクラスが一意という条件は満たしていますが、1つのクラスファイルから複数個の Class をロードできる、という例でした。

追記

上記コード

-    private static Object newInstance() throws Exception {
+    private static Singleton newInstance() throws Exception {

-        return new ClassLoader() {
+        return (Singleton) new ClassLoader() {

のように変更すると、もちろんコンパイルは通るんですが、実行すると

Exception in thread "main" java.lang.ClassCastException: Singleton cannot be cast to Singleton
        at test.newInstance(test.java:10)
        at test.main(test.java:4)

という、世にも奇妙な例外を吐き出してきます。

やっぱり素人にはお勧めできない。

댓글 없음:

댓글 쓰기