Ist Java zu Inline-String-Konstanten gewährleistet, wenn sie zum Zeitpunkt der Kompilierung bestimmt werden können

StackOverflow https://stackoverflow.com/questions/1406616

  •  05-07-2019
  •  | 
  •  

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.

War es hilfreich?

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:

  1. 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.
  2. 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?

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top