ist es möglich, zu deaktivieren javac ist inlining von static-final-Variablen?
Java statische compiler (javac) inlines einige static final-Variablen und bringt die Werte direkt in den Konstanten-pool. Betrachten Sie das folgende Beispiel. Klasse A definiert einige Konstanten (public static final-Variablen):
public class A {
public static final int INT_VALUE = 1000;
public static final String STRING_VALUE = "foo";
}
Klasse B verwendet diese Konstanten:
public class B {
public static void main(String[] args) {
int i = A.INT_VALUE;
System.out.println(i);
String s = A.STRING_VALUE;
System.out.println(s);
}
}
Beim kompilieren der Klasse B, javac bekommt die Werte dieser Konstanten aus der Klasse A und inlines diese Werte in B.class. Als Ergebnis, die Abhängigkeit B hatte die Klasse zur compile-Zeit werden gelöscht, aus dem bytecode. Dies ist ein eher eigenartiges Verhalten, weil Sie das Backen in der die Werte dieser Konstanten zu der Zeit der Zusammenstellung. Und Sie würden denken, dass dies ist eine der einfachsten Dinge, die der JIT-compiler zur Laufzeit.
Gibt es eine Möglichkeit oder irgendwelche versteckten compiler-option, mit der Sie diese Funktion deaktivieren inlining Verhalten von javac? Für den hintergrund, wir suchen zu tun bytecode-Analyse für die Abhängigkeit Zwecke, und es ist einer der wenigen Fälle, wo der bytecode-Analyse schlägt fehl, zu erkennen, compile-time Abhängigkeiten. Danke!
Bearbeiten: dies ist eine leidige Angelegenheit, weil wir in der Regel nicht alle Steuern auf die Quelle (z.B. third-party Bibliotheken, die Definition von Konstanten). Wir sind daran interessiert, die Erkennung dieser Abhängigkeiten, die aus der Perspektive der mit der Konstanten. Da die Referenz wird gelöscht, der code, der verwendet die Konstanten, es gibt keinen einfachen Weg, um Sie zu erkennen, kurz, tun, source-code-Analyse.
- Gute Frage!!! Irgendwann in dieser inlining von Konstanten verursachen seltsame Probleme... Aber ich habe nicht gesehen, eine richtige Art und Weise zu beschränken.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Element 93 von Java-Teilnehmer (Joshua Bloch) sagt, dass Sie arbeiten können, um diese durch die Verhinderung der endgültige Wert wird als konstant angenommen. Zum Beispiel:
Natürlich nichts von alledem ist relevant, wenn Sie keinen Zugriff auf den code, der definiert die Konstanten.
ident
statttoX
.String.valueOf()
)System.out
ist diese:public final static PrintStream out = nullPrintStream();
(der eigentliche stream ist später von native code).nullPrintStream()
gibt null zurück, wenncurrentTimeMillis()>0
. Es schlug nie mich, warum Sie das getan hat (im Gegensatz zu nur...out = null;
), bis jetzt. Natürlich hätte ich Bock auf Lesen Sie die Dokumentation fürnullInputStream()
wäre es gewesen, klar zu machen...javac
Krüppel, die Möglichkeit zu schaffen, einen richtigen debugger.PrintStream
noch dienull
Referenz kann immer sein compile-time-Konstanten, das inlining nur zu verweisen können, JIT, aber der JIT ist nicht egal, wo der Wert kam von vor der Zuweisung. Beachten Sie, dass beginnend mit Java 7 code nicht Aussehenpublic final static PrintStream out = null;
.public static final int INT_VALUE; public static final String STRING_VALUE; static { INT_VALUE = 1000; STRING_VALUE = "foo"; }
vermeidet unnötige Methodenaufrufe, nicht zu reden von den Boxen overheadInteger.valueOf(1000)
.Glaube ich nicht so. Die einfachste Lösung wäre, setzen diese Eigenschaften eher als Felder:
Vergessen Sie nicht, dass in bestimmten Fällen das inlining ist unerlässlich, um die Verwendung der Wert - zum Beispiel, wenn Sie auf
INT_VALUE
als ein Fall in einem switch-block, der hat angegeben werden, da ein konstanter Wert.final
(das Ergebnis konnte festgestellt werden, zur compile-Zeit), die im wesentlichen die Wiederherstellung despublic static final
Szenario? (spekulative Begründung meinerseits)return null;
) würde erfordern, dass Sie neu kompilieren aller Klassen nutzen Sie, nachdem Sie gekommen, um zu implementieren, die Methode.final
Modell überflüssig ... aus rein sprachlichen Sinne. (Stil überlegungen etwas anderes sagen, aber die JLS ist nicht versucht, Sie zu einer Stil-Handbuch.)Stoppen inlining Sie brauchen, um die Werte nicht-compile-Zeit-Konstanten (der Begriff JLS). Sie können dies tun, ohne die Verwendung von Funktionen und erstellen ein minimum von bytecode durch die Verwendung eines
null
im initialiser Ausdruck.Obwohl es sehr literal im code generation
javac
optimieren sollte dies ein push von einem unmittelbaren integer gefolgt von einem store, um das statische Feld in der static initialiser.1000
so funktioniert es in einer case-Anweisung, aber dann wird es auch inline. Der magic in der Antwort ist, dassnull
ist nicht compile-Zeit-Konstante und daher kein Ausdruck, der verwendet, es ist entweder.public static final int INT_VALUE; static { INT_VALUE = 1000; }
null!=null?0:
zeigt deutlich eine Absicht zu tun, etwas so ist es weniger wahrscheinlich, getrennt werden, durch einen Reiniger. Obwohl die Redewendung nicht offensichtlich ist, sollte es nicht lange dauern, um herauszufinden, was das Ergebnis ist, wenn auch nicht der compile-Zeit-Konstante Semantik*. Es ist nicht völlig entstellt, indem Neuformatierung. Sie nicht haben, um match-IDS (passen Sie? don ' T Sie? Es ist eine seltsame Schreibweise, was?).null!=null
sinnvoll ist, sollte keine Probleme mit dem Verständnis der Unterschied zwischen compile-Zeit-Konstanten und-Variablen zugeordnet, die in einem Initialisierer. Seit einstatic final
variable nicht sofort zugeordnet muss zugewiesen bekommen, die in einer statischen Initialisierer und es muss genau einmal zugeordnet, kann der compiler überprüfen. Es ist die standard-idiom für Initialisierungen passt nicht in einen Ausdruck.JLS 13.4.9 mit diesem Thema umgeht. Ihre Empfehlung ist grundsätzlich zu vermeiden compile-Zeit-Konstanten, wenn der Wert in irgendeiner Weise ändern dürfte.
Ich denke, das ist eine ernst bug. Java ist kein C/C++. Es ist ein Prinzip(oder auch nicht) "Compile once, run everywhere".
In diesem Fall, wenn Eine Klasse geändert wird. Alle Klassen referenzieren A. CONST_VALUE müssen neu kompiliert werden und Sie kaum wissen, ob Eine Klasse geändert wird.
static
Feld statt mit einem Wert. Aber stellen Sie sich vor, wie einswitch
Aussage über die Konstanten der anderen Klasse sollte dann kompiliert, wenn es sollte zur Unterstützung von änderungen nach der Kompilierung. Ebenso ist die Sprache ist streng, wenn es um code-Erreichbarkeit. Ermöglicht Konstanten zu ändern, nach der Zusammenstellung würde die Niederlage der Sprache Sicherheit. Und es ist konsequent zu zwingen, alle verwendet, eine Konstante zu verwenden, die eine Konstante, anstatt zu Lesen, ein dynamischer Wert.switch
- Anweisung zu ändern, nach der Zusammenstellung? Ich denke nicht so.switch
Aussagen erfordern immer noch constant Etiketten. Das ist wie switch funktioniert. Wenn Sie möchten, dass "ein array initialisiert mit Ausdrücken" statt oder einige hashing-Struktur, bewältigen kann, ändern von Schlüsseln, gut, einfach umzusetzen. "Viele Wege" Aber nicht die Schuld von Java nicht zu tun, ist etwas ganz anderes als schreiben in den source-code.switch
- Anweisung.Rewrite-Klasse Ein wie:
jmake ist ein open-source-Projekt, das behauptet, die ganze Arbeit, die Verfolgung der Abhängigkeiten zwischen Java-Dateien und inkrementell kompilieren die minimale erforderliche Menge von Dateien. Er behauptet richtig zu verarbeiten, die änderungen an static final-Konstanten, auch wenn Sie manchmal benötigt das gesamte Projekt neu kompiliert werden. Es meistert sogar änderungen an einer feineren Granularität als die classfiles; wenn (beispielsweise) die Signatur einer Methode C. m() ändert, dann ist es nur neu kompiliert die Klassen, die tatsächlich davon abhängen, m (), anstatt alle Klassen, die Nutzung von C.
DISCLAIMER: ich habe keine Erfahrung mit jmake.
Kurzem stieß ich auf eine ähnliche Problem, und, wie es oben gesagt wurde, wie inlining umgangen werden kann mit nicht-compile-time Ausdrücke, sagen:
wo die
constOf
Methode Familie ist nur:Dieser ist ein wenig kürzer als andere Vorschläge wie
Integer.valueOf(1000).intValue()
odernull!=null?0: 1000
Fühle ich java eng stützt sich auf die dynamische Kompilierung und es nicht tun, keine Lust auf Zusammenstellung Logik wie C++.
können Sie versuchen, einige Optionen mit JIT-Compilern, die nicht Laufzeit-Optimierung haben können, einige Optionen zu deaktivieren/aktivieren dieser.
in Verzug javac können Sie nicht bekommen, dass die option. Sie haben zu verwenden
1. irgendeine Art von dependency graph wie erweitert oder implementiert
2. mit der Methode basiert Verlinkung.
-s