2015-06-29 4 views
1

Исходя из мира Java, одним из самых популярных программных текстов является «Эффективная Java» Джошуа Блоха.Можете ли вы сломать синглтон Scala (объект)?

Одна из многих тем, в этой книге инструктируют программист предпочитающих перечислений на основе одиночек в стандартные реализации одноплодных, так как большинство стандартных реализаций могут быть сломаны с помощью сериализации, клонирования и т.д.

Моего вопроса

Может ли стандартный синтаксис Scala, который, как представляется, определяется с помощью «объекта», а не «класса», может быть нарушен с помощью подобных трюков? Или он защищен средой времени выполнения, подобно тому, как singleton находится в Java?

+0

Что именно вы подразумеваете под сломанным? –

+0

В принципе, со стандартной реализацией, где у вас есть статическая переменная, лениво инициализированная семантикой check-then-create, вы можете получить более одного экземпляра синглтона, сериализуя оригинал, а затем десериализируя его в другую переменную. Существуют и другие аналогичные способы разбить шаблон, когда перечисление не используется. –

+0

Короткий ответ ДА. Все это реализовано на уровне языка, и оно свободно от всей церемонии, которую мы должны сделать на Java. Я не могу предоставить ссылку на ресурс, но я слышал об этом на техническом разговоре. –

ответ

3

Если вы достаточно стараетесь, то ничего не остановит вас от копирования любого объекта, включая значения перечисления, на Java. Однако, поскольку вы не можете создать экземпляр enum с использованием «нормального» отражения, вам нужно немного углубиться в окно инструмента хакера: sun.misc.Unsafe. Это только используется при создании экземпляра, остальное может быть сделано с нормальным отражением:

Unsafe unsafe = ...; // Obtain the value of the sun.misc.Unsafe.theUnsafe field, using normal reflection 
    try 
    { 
     Object o = unsafe.allocateInstance(TestEnum.class); // creates a new instance of TestEnum with all fields set to 0/false/null 
     System.out.println(o); // prints 'null' because the name field is null 
     System.out.println(o.getClass()); // prints 'JavaTest$Enum' 

     Field f = Enum.class.getDeclaredField("name"); 
     f.setAccessible(true); // bypasses the final and access checks 
     f.set(o, "TEST"); // set the name to 'TEST' 
     f = Enum.class.getDeclaredField("ordinal"); 
     f.setAccessible(true); 
     f.set(o, 1); // set the ordinal to 1 

     System.out.println(o); // prints 'TEST' 
     System.out.println(((Enum) o).ordinal()); // prints 1 
    } 
    catch (Exception ex) 
    { 
     ex.printStackTrace(); 
    } 

Кроме того, вы можете скопировать поля из Инстанция TestEnum к новому экземпляру TestEnum. Это можно сделать либо вручную, как показано выше (по баловаться с параметрами до f.set(o, ...) чуть позже) или цикл через все поля и копировать их, например, так:

for (Field f : TestEnum.class.getDeclaredFields()) 
{ 
    if (!Modifiers.isStatic(f.getModifiers()) 
    { 
     f.setAccessible(true); 
     f.set(o, f.get(TestEnum.INSTANCE)); 
    } 
} 

Конечно это только копии полей в TestEnum класс, который в моем случае не имеет полей. Возможно, вы захотите скопировать поля в Enum, так как они не обрабатываются этим циклом for.

Чтобы дать правильный ответ на ваш вопрос: Да, вы можете разбить Scala object столько, сколько вы можете сломать enum. Все зависит от того, сколько усилий вы готовы предпринять и насколько велико ваш незаконный арсенал кода.

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