2014-09-11 3 views
1

У меня есть класс Singleton, который реализован с инициализацией по требованию. Согласно статье this, она по-прежнему уязвима для отражений.Как избежать использования отражений для создания нового экземпляра

Как я могу помешать этому из java-отражений вызывать частный конструктор и создавать новые экземпляры?

Это мой SingletonTest класс:

class SingletonTest{ 
    public SingletonTest(){ 
     System.out.println("before SingletonTest()"); 
     Singleton s1 = Singleton.getSingleton(); 
     Singleton s2 = Singleton.getSingleton(); 

     System.out.printf("s1 Hash: %d\n",System.identityHashCode(s1)); 
     System.out.printf("s2 Hash: %d\n",System.identityHashCode(s2)); 

     Constructor<?> con = Singleton.class.getDeclaredConstructors()[1]; 
     con.setAccessible(true); 

     //System.out.println(con.toString()); 

     try { 
      Singleton s3 = (Singleton) con.newInstance(); 
      System.out.printf("s3 Hash: %d\n",System.identityHashCode(s3)); 
     } catch (Exception ex) { 
      ex.printStackTrace(); 
     } 

     System.out.println("after SingletonTest()"); 
    } 

    public static void main(String[] args){ 
     new SingletonTest(); 
    } 
} 

Это мой Singleton класс:

final public class Singleton { 
    private Singleton(){ 
     System.out.println("Singleton created...!"); 
    } 

    public static Singleton getSingleton(){ 
     return SingletonHolder.INSTANCE; 
    } 

    static class SingletonHolder{ 
      private static final Singleton INSTANCE = new Singleton(); 
    } 

    public void doStuff(){ 
     System.out.println("dostuff...."); 
    } 

} 

Выход:

before SingletonTest() 
Singleton created...! 
s1 Hash: 1924489565 
s2 Hash: 1924489565 
Singleton created...! 
s3 Hash: 294316734 
after SingletonTest() 

ответ

1

как о проверке и бросить исключение в конструкторе?

private Singleton(){ 
    if(SingletonHolder.INSTANCE !=null) 
     throw new IllegalStateException("Not allowed!"); 
} 

другой возможность есть, реализовать ваш одноэлементный узор с помощью java Enum.

public enum Singleton { 
    INSTANCE; 
    public void doStuff(){...} 

} 
+0

спасибо Это работает :); Я попробовал 'java.lang.InstantiationException', который не является исключением RunTimeException. Я где-то читал, что вы можете управлять им с помощью SecurityManager. Есть идеи на это? –

+0

@tiriboy как насчет броска 'InstantiationError'? Или вы хотите, чтобы это было «RuntimeEx», просто «новое RuntimeException()»? или я тебя не понял? – Kent

+0

Да, это кажется более самоописываемым. Тпй. –

Смежные вопросы