Wie kann das Entfernen des endgültigen Schlüsselworts das Verhalten eines Programms verändern?

8

Diese Frage bezieht sich nicht primär auf Strings. Aus wissenschaftlicher Neugier möchte ich wissen, wie der Modifikator final auf einer Variablen das Verhalten eines Programms verändern kann. Das folgende Beispiel zeigt, dass es möglich ist.

Diese Zeilen drucken true

%Vor%

aber diese Zeilen drucken false

%Vor%

Gibt es neben String interning noch weitere Dinge, die dazu führen können, dass sich das Verhalten eines Programms ändert, wenn der Modifizierer final aus einer Variablendeklaration entfernt wird? Ich gehe davon aus, dass das Programm mit oder ohne Modifikator kompiliert.

Bitte stimmen Sie nicht ab, um es als Duplikat von zu schließen Strings mit == vergleichen, die in Java als final deklariert werden . Ich verstehe das String s Beispiel.

Ich frage, ob es andere Gründe gibt, einen final Modifikator zu entfernen, kann einen Unterschied machen. Bitte kann jemand auf eine Antwort verlinken oder die Frage beantworten. Vielen Dank.

    
Paul Boddington 22.03.2015, 21:37
quelle

1 Antwort

5

Der Modifizierer final stellt nur sicher, dass die Variable definitiv zugewiesen , und verbietet jede Neuzuweisung zu und von dieser Variable.

Die einzigen speziellen Fälle, die beobachtet werden können, sind ausdrücklich in der JLS angegeben :

  

Eine Variable vom primitiven Typ oder Typ String, die final ist und mit einem konstanten Ausdruck zur Kompilierungszeit initialisiert wird (§15.28), wird als konstante Variable bezeichnet.

     

Ob eine Variable eine konstante Variable ist oder nicht, kann Auswirkungen auf die Klasseninitialisierung (§12.4.1), die Binärkompatibilität (§13.1, §13.4.9) und die eindeutige Zuweisung (§16) haben.

Es gibt eine anständige Menge an JLS-Lektüre und um den Hauptpunkt zu behandeln: By JLS §13.4.9 , werden nicht beim Entfernen der% co_de irgendwelche negativen Auswirkungen haben % Modifikator.

Allerdings von JLS 17.5 Wenn Sie sich auf die Garantie eines Threads verlassen, nur die definitiv zugewiesenen Variablen in einem Objekt zu sehen, das beobachtet werden kann, dann wird das Entfernen der Variable final dazu führen, dass diese Variablen für einen anderen Thread nicht mehr sichtbar sind.

Also, wenn wir uns Klasseninitialisierung Zuerst gibt es Regeln für die Klasseninitialisierung, wenn das Feld statisch und nicht eine konstante Variable ist:

  

Ein Klassen- oder Schnittstellentyp T wird unmittelbar vor dem ersten Auftreten eines der folgenden Ereignisse initialisiert:

     
  • T ist eine Klasse und eine Instanz von T wird erstellt.
  •   
  • T ist eine Klasse und eine durch T deklarierte statische Methode wird aufgerufen.
  •   
  • Ein statisches Feld, das von T deklariert ist, wird zugewiesen.
  •   
  • Es wird ein statisches Feld verwendet, das von T deklariert wird, und das Feld ist keine konstante Variable (§4.12.4).
  •   

In JLS §13.1 ist es Ausgesprochen, dass das Ändern eines Felds in final brechen kann Binärkompatibilität :

  

Verweise auf Felder, die konstante Variablen sind (§4.12.4), werden zur Kompilierzeit auf den angegebenen konstanten Wert aufgelöst. Kein Verweis auf ein solches Feld sollte in dem Code in einer Binärdatei vorhanden sein (außer in der Klasse oder der Schnittstelle, die das Feld enthält, das einen Code haben wird, um es zu initialisieren). Ein solches Feld muss immer als initialisiert erscheinen (§12.4.2); Der Standardwert für den Typ eines solchen Feldes darf niemals eingehalten werden. Siehe § 13.4.9 für eine Diskussion.

Ab 13.4.9:

  

Wenn ein Feld, das nicht als endgültig deklariert wurde, geändert wird, um deklariert zu werden   Endgültig, dann kann es Kompatibilität mit bereits vorhandenen Binärdateien brechen   Versuchen Sie, dem Feld neue Werte zuzuweisen.

     

Löschen Sie das Schlüsselwort final oder ändern Sie den Wert, zu dem ein Feld gehört   initialisiert nicht die Kompatibilität mit vorhandenen Binärdateien.

     

Wenn ein Feld eine konstante Variable ist (§4.12.4), löschen Sie das Schlüsselwort   final oder Ändern seines Wertes wird die Kompatibilität mit nicht brechen   Vorhandene Binärdateien, indem sie verursachen, dass sie nicht laufen, aber sie werden nicht   einen neuen Wert für die Verwendung des Felds sehen, sofern dies nicht der Fall ist   neu kompiliert. Dies gilt auch dann, wenn die Verwendung selbst keine ist   Kompilierzeitkonstantenausdruck (§15.28).

     

Dieses Ergebnis ist ein Nebeneffekt der Entscheidung, konditional zu unterstützen   Zusammenstellung, wie am Ende von §14.21 diskutiert.

Achte also darauf, die Felder plötzlich in final zu ändern. Entfernen das Feld ist sicher .

... aber das gilt nur für eine single-threaded Welt. Von JLS 17.5 :

  

Felder, die als final deklariert sind, werden einmal initialisiert, aber nie geändert   normale Umstände. Die detaillierte Semantik der Endfelder ist   etwas anders als bei normalen Feldern. Bestimmtes,   Compiler haben eine große Freiheit, die Lesevorgänge der letzten Felder zu verschieben   über Synchronisationsbarrieren und Aufrufe an beliebige oder unbekannte   Methoden. Entsprechend dürfen Compiler den Wert von a behalten   Letztes Feld in einem Register zwischengespeichert und nicht aus dem Speicher in neu geladen   Situationen, in denen ein nicht endgültiges Feld neu geladen werden müsste.

     Mit

final fields können Programmierer auch Thread-safe unveränderlich implementieren   Objekte ohne Synchronisation.Ein Thread-sicheres unveränderliches Objekt ist   von allen Threads als unveränderbar angesehen, selbst wenn ein Datenrennen zum Bestehen verwendet wird   Verweise auf das unveränderliche Objekt zwischen Threads. Dies kann zur Verfügung stellen   Sicherheitsgarantien gegen Missbrauch einer unveränderlichen Klasse durch falsche oder   Schadcode. Die letzten Felder müssen korrekt verwendet werden, um a   Garantie der Unveränderbarkeit.

     

Ein Objekt wird als vollständig initialisiert betrachtet, wenn es   Konstruktor endet. Ein Thread, der nur einen Verweis auf einen   Objekt, nachdem das Objekt vollständig initialisiert wurde, ist garantiert   um die korrekt initialisierten Werte für das Finale dieses Objekts anzuzeigen   Felder.

Wenn also Ihr Programm von der obigen Garantie abhängig ist, damit es normal funktioniert, dann hat das Entfernen des final -Schlüsselwortes Konsequenzen beim Threading.

    
Makoto 22.03.2015, 22:21
quelle

Tags und Links