Java中反射和Unsafe破壞單例設計模式


有如下單例模式設計代碼:

class Singleton
{
    private String info = "HELLO SHIT";

    private static Singleton instance;

    private Singleton()
    {
        System.out.println("******實例化對象******");
    }

    public static Singleton getInstance()
    {
        synchronized (Singleton.class)
        {
            if (instance == null)
            {
                instance = new Singleton();
            }
        }
        return instance;
    }

    public void show()
    {
        System.out.println("www.google.com");
    }
}

按照規則,我們只能獲取一個實例化的對象,如下面的代碼:

public class Hello
{
    public static void main(String[] args) throws Exception
    {
        Singleton instanceA = Singleton.getInstance();
        Singleton instanceB = Singleton.getInstance();
        System.out.println(instanceA.hashCode());
        System.out.println(instanceB.hashCode());
        System.out.println(instanceA == instanceB);
    }
}

程序輸出:

******實例化對象******
685325104
685325104
true

Process finished with exit code 0

可以看到instanceA和instanceB完全相同.

下面演示用反射獲取單例的構造函數,並且實例化出多個對象:

public class Hello
{
    public static void main(String[] args) throws Exception
    {
        Constructor c = Singleton.class.getDeclaredConstructor();
        c.setAccessible(true);

        Singleton instanceA = (Singleton)c.newInstance();
        Singleton instanceB = (Singleton)c.newInstance();
        System.out.println(instanceA.hashCode());
        System.out.println(instanceB.hashCode());
        System.out.println(instanceA == instanceB);
    }
}

程序輸出:

******實例化對象******
******實例化對象******
685325104
460141958
false

Process finished with exit code 0

可以看到,這里調用了兩次構造函數,實例化了兩個不同的Singleton對象。

 

除了用反射,我們還可以用Unsafe類實例化多個單例對象,這種方式和反射的區別在於:Unsafe不需要調用構造函數。因為Unsafe是使用C++進行JVM底層控制。代碼如下:

public class Hello
{
    public static void main(String[] args) throws Exception
    {
        Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
        theUnsafeField.setAccessible(true);
        Unsafe unsafeInstance = (Unsafe)theUnsafeField.get(null);
        Singleton instanceA = (Singleton)unsafeInstance.allocateInstance(Singleton.class);
        Singleton instanceB = (Singleton)unsafeInstance.allocateInstance(Singleton.class);
        System.out.println(instanceA.hashCode());
        System.out.println(instanceB.hashCode());
        System.out.println(instanceA == instanceB);
    }
}

程序輸出:

460141958
1163157884
false

Process finished with exit code 0

可以發現上面的代碼根本沒有調用Singleton的構造函數,而是直接生成了兩個實例。

 

其實上面的代碼並沒有太大意義,只是作為知識點可以加深對反射和單例的理解和印象。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM