Ist Java zu Inline-String-Konstanten gewährleistet, wenn sie zum Zeitpunkt der Kompilierung bestimmt werden können
Frage
Betrachten wir diesen Fall:
public Class1 {
public static final String ONE = "ABC";
public static final String TWO = "DEF";
}
public Class2 {
public void someMethod() {
System.out.println(Class1.ONE + Class1.TWO);
}
}
Normalerweise würde man erwarten, der Compiler die ein und zwei Konstanten Inline. Allerdings ist dieses Verhalten gewährleistet? Können Sie zur Laufzeit Class2 ohne Class1 implementieren in dem Classpath, und erwarten, dass es unabhängig von Compiler zu arbeiten, oder ist dies eine optionale Compiler-Optimierung?
EDIT: Warum auf der Erde tun? Nun, ich habe eine Konstante, das zwischen zwei Enden einer Anwendung (Client und Server über RMI) geteilt werden würde und es würde in diesem Fall sehr praktisch sein, die konstant auf einer Klasse zu setzen, die nur auf einer Seite dieser Kluft sein können ( wie es ist logisch derjenige, dass konstanter Wert besitzt), anstatt es in einer beliebigen konstanten Klasse hat, nur weil es von beiden Seiten des Code geteilt werden muss. Bei der Kompilierung seine alle einen Satz von Quelldateien, aber zum Zeitpunkt der Erstellung wird durch Paket geteilt.
Lösung
Es ist garantiert als konstanter Ausdruck behandelt werden, und von Abschnitt 15.28 des JLS :
Ein Kompilierung-Konstante Ausdruck ein Ausdruck bezeichnet einen Wert von primitiver Typ oder ein String, der tut Ergänzen nicht abrupt und ist aus nur mit dem folgenden:
- Literale primitiver Art und Literale vom Typ String (§3.10.5)
- Casts auf primitive Typen und wirft String eingeben
- Die unären Operatoren +, -, ~ und! (Aber nicht ++ oder -)
- Die multiplikativen Operatoren *, / und%
- Die additiven Operatoren + und -
- ...
...
Compiler-Konstanten vom Typ String sind immer „interniert“, um zu teilen eindeutige Instanzen, wobei das Verfahren unter Verwendung von String.intern.
Nun, das nicht ganz sagen, dass es garantiert ist inlined werden. Abschnitt 13.1 der Spezifikation jedoch sagt:
Verweise auf Felder, die konstant sind Variablen (§4.12.4) aufgelöst in Zeit auf den konstanten Wert kompilieren das heißt bezeichnet. Kein Hinweis auf diese ein konstantes Feld sollte vorhanden sein, in der Code in einer Binärdatei (außer in die Klasse oder Schnittstelle enthält, die Gleichfeld, das Code haben zu initialisieren), und eine solche Konstante Felder müssen immer gewesen erscheinen initialisiert; der Standard-Anfangswert für die Art eines solchen Feldes muss nie beobachtet werden.
Mit anderen Worten: auch wenn der Ausdruck selbst war keine Konstante , sollte es keinen Bezug Class1
. Also ja, du bist in Ordnung. Das bedeutet nicht, unbedingt Garantie, dass der verketteten Wert im Bytecode verwendet wird, aber die Bits früher garantieren verwiesen, dass der verketteten Wert interniert wird, so würde ich mich sehr groß überrascht wenn es hat inline nicht nur den verketteten Wert. Auch wenn es nicht der Fall ist, sind Sie garantiert, dass es ohne Class1
arbeiten werden.
Andere Tipps
Das Kompilieren, dass mit javac 1.6.0_14 die folgenden Bytecode erzeugt:
public void someMethod();
Code:
0: getstatic #2; //Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3; //String ABCDEF
5: invokevirtual #4; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
So die Saiten bei der Kompilierung verkettet und das Ergebnis wird in Class2 Konstante Pool enthalten.
Es wird nicht vom Compiler, sondern durch den Interpreter zur Laufzeit und, wenn möglich, umgerechnet in Assembler-Code inlined werden.
Es kann nicht garantiert werden, da nicht alle Dolmetscher (JVM) auf die gleiche Weise arbeiten. Aber die wichtigsten Implementierungen tun.
Leider habe ich keinen Link zu diesem erhalten :(
Ich vermute, weiß aber nicht sicher, dass dies funktionieren wird, aber es klingt nicht wie eine gute Idee.
Die "normalen" Wege, dies zu tun, sind:
- Legen Sie die Konstanten in einem Paket, das zwischen dem Client und dem Server freigegeben wird. Vermutlich gibt es ein solches Paket, weil das ist, wo die Schnittstellen gehen.
- Wenn es kein solches Paket erstellen 2 Klassen mit dem gemeinsam genutzten Konstanten: ein für den Server und einen für die Kunden.
Siehe JLS 13.4.9 . Es ist zwar nicht ausdrücklich verlangt, dass Konstanten durch den Compiler inlined ist, deutet darauf, dass die bedingte Kompilierung und Unterstützung für die Konstanten in switch
Anweisungen bewirken, dass der Compiler immer Inline-Konstanten.
Es sieht aus wie Sie Ihre eigene Version der in enum
eingebaute Fähigkeit Codierung, die für Sie nicht public static final
, korrekte Namensgebung über name()
und toString()
(sowie einige andere Vorteile haben, aber vielleicht den Nachteil eines größeren Speicher Footprint).
Sind Sie eine ältere Version von Java verwenden, die nicht Enum enthält noch?