2015-01-16 27 views
17

Może to zabrzmi trochę dziwnie, ale czy w czasie wykonywania można dodać modyfikator final?Dodaj ostateczny modyfikator w środowisku wykonawczym w Javie

Mam zmienną, która jest oznaczona jako public static int/short. W pewnym momencie chcę zapobiec zmianie jego wartości i chcę zachować jego dostępność jako standardowej wartości statycznej (ClassName.field).

public class Main { 

    private static int a = 0; 

    public static void addFinalMod(Field f) { 

     Field modifiersField = null; 
     try { 
      modifiersField = Field.class.getDeclaredField("modifiers"); 
     } 
     catch (NoSuchFieldException e) { 
      e.printStackTrace(); 
     } 
     modifiersField.setAccessible(true); 
     try { 
      modifiersField.setInt(f, f.getModifiers() & Modifier.FINAL); 
     } 
     catch (IllegalAccessException e) { 
      e.printStackTrace(); 
     } 
    } 

    public static void main(String[] args) { 

     System.out.println(a); 
     try { 
      Field f = Main.class.getDeclaredField("a"); 
      addFinalMod(f); 
     } 
     catch (NoSuchFieldException e) { 
      e.printStackTrace(); 
     } 
     a = 10; //I was expecting error/exception here 
     System.out.println(a); 
    } 

wyjściowa:

0 
10 
+1

To całkiem interesujące pytanie. Na razie wydaje mi się, że reguły 'final' są sprawdzane tylko podczas kompilacji (dotyczy to zarówno wymagań inicjalizacyjnych, jak i gwarancji JMM). –

+3

Myślę, że masz na myśli 'f.getModifiers() | Modifier.FINAL' zamiast 'f.getModifiers() & Modifier.FINAL', aby pozostały inne modyfikatory. Również jeśli użyjesz 'f.set (null, 5); 'dostaniesz oczekiwany wyjątek. – Pshemo

Odpowiedz

32

W pewnym momencie chcę zapobiec zmieniając jego wartość

zrobić w logice aplikacji. Zmodyfikuj zmienną tylko za pomocą metod. Zachowaj flagę śledzącą dowolną zmianę zmiennej. Po wprowadzeniu zmiany lub osiągnięciu wartości w pewnym punkcie podnieś flagę i wyślij wyjątek dla kolejnych prób zmiany zmiennej.

final to słowo/funkcja językowa do pisania kodu źródłowego i zapobiegania ponownemu przypisaniu zmiennej w kodzie źródłowym. W czasie wykonywania robi (prawie) nic.

+1

Tak też bym zrobił, dodałem, że chciałbym zobaczyć prawdziwe rozwiązanie, ale wątpię, czy to możliwe. –

+1

Awans i punkt ciasteczkowy dla "(prawie)" :) – yshavit

+1

Wiem, to rozwiązanie zadziała i jest bardzo łatwe do wdrożenia. ale wolałbym nie używać żadnych metod. – user2749903

1

Użyj niezmienny obiekt:

public class Thing { 
    private int value; 
    public Thing(int value) { this.value = value; } 
    public int getValue() { return this.value; } 
} 

Następnie wystarczy zastąpić ją, gdy wymaga modyfikacji:

Thing x = Thing(1); 
// do some stuff 
x = Thing(2); 
// more stuff 

Jeśli myślisz: „Ale to mogą jeszcze zmienić wartość zastępując obiekt!" Ależ oczywiście. Jedynym sposobem, aby temu zapobiec, jest zablokowanie jakiegoś globalnego stanu (który jest faktycznie niemożliwy, jeśli nie jest stały), ale nie używasz globalnego stanu, prawda? Stan globalny jest Bad Thing TM.

Stan globalny ma bardzo prosty problem: sprawia, że ​​kod jest mniej przydatny do wielokrotnego użytku i bardziej podatny na błędy. Błąd podatny jest szczególnie prawdziwy, jeśli modyfikujesz ten stan globalny w środowisku wykonawczym. "Aw, cholera, wszystko dzieje się w złej kolejności." Nie masz pojęcia, jakie to łatwe. Próba śledzenia kolejności zdarzeń jest powodem, dla którego mutlithreading jest tak trudny. Jeśli chodzi o możliwość ponownego użycia, oznacza to, że nie możesz mieć dwóch niezależnych instancji, co z kolei oznacza, że ​​nie możesz mieć żadnych dwóch wystąpień czegoś, co od tego zależy (przynajmniej wtedy, gdy okazuje się, że potrzebujesz zmienić w końcu to coś).

Nawet jeśli nie jest to globalne, to jest to dziwny stan, że każdy, kto musi zmodyfikować swój kod (w tym siebie), będzie musiał być świadomy i myśleć o tym, kiedy wprowadza zmiany. Czy to brzmi tak, jakby zmieniało się łatwiej lub trudniej? (Podpowiedź: ten drugi.) Nie rób tego samemu sobie lub współpracownikom. Ułatw to. Zrób lekcję z Zen of Python: "Prostota jest lepsza niż skomplikowana".

Tak więc w dolnej linii: jeśli potrzebujesz niezmiennego obiektu, użyj niezmiennego obiektu. Jeśli potrzebujesz niezmiennej globalności, która nie jest stała, znajdź lepszy sposób na uporządkowanie kodu.