Ich bin erstaunt, dass niemand einen echten Code gepostet hat, der dekompiliert wurde, um zu beweisen, dass es zumindest einen kleinen Unterschied gibt.
Als Referenz wurde dies gegen javac
Version getestet 8
, 9
und 10
.
Angenommen, diese Methode:
public static int test() {
/* final */ Object left = new Object();
Object right = new Object();
return left.hashCode() + right.hashCode();
}
Wenn Sie diesen Code so kompilieren, wie er ist, wird genau derselbe Bytecode erzeugt, als wenn final
er vorhanden gewesen wäre ( final Object left = new Object();
).
Aber dieser:
public static int test() {
/* final */ int left = 11;
int right = 12;
return left + right;
}
Produziert:
0: bipush 11
2: istore_0
3: bipush 12
5: istore_1
6: iload_0
7: iload_1
8: iadd
9: ireturn
Weggehen final
Gegenwart erzeugt werden:
0: bipush 12
2: istore_1
3: bipush 11
5: iload_1
6: iadd
7: ireturn
Der Code ist so gut wie selbsterklärend. Wenn es eine Kompilierungszeitkonstante gibt, wird er direkt auf den Operandenstapel geladen (er wird nicht wie im vorherigen Beispiel über in einem Array mit lokalen Variablen gespeichert bipush 12; istore_0; iload_0
) - was sinnvoll ist da kann es niemand ändern.
Auf der anderen Seite istore_0 ... iload_0
ist es mir ein Rätsel, warum der Compiler im zweiten Fall nicht produziert . Es ist nicht so, dass dieser Slot 0
in irgendeiner Weise verwendet wird (es könnte das Variablenarray auf diese Weise verkleinern, aber möglicherweise fehlen mir einige interne Details, kann nicht sicher erzählen)
Ich war überrascht, eine solche Optimierung zu sehen, wenn man bedenkt, wie wenig es javac
tut. Wie sollen wir immer verwenden final
? Ich werde nicht einmal einen JMH
Test schreiben (den ich anfangs wollte), ich bin mir sicher, dass der Unterschied in der Reihenfolge liegt ns
(wenn möglich überhaupt erfasst werden). Der einzige Ort, an dem dies ein Problem sein könnte, ist, wenn eine Methode aufgrund ihrer Größe nicht inline gesetzt werden konnte (und das Deklarieren final
diese Größe um einige Bytes verkleinern würde).
Es gibt zwei weitere final
, die angegangen werden müssen. Erstens, wenn eine Methode final
(aus einer JIT
Perspektive) ist, ist eine solche Methode monomorph - und dies sind die beliebtesten von der JVM
.
Dann gibt es final
Instanzvariablen (die in jedem Konstruktor festgelegt werden müssen); Diese sind wichtig, da sie eine korrekt veröffentlichte Referenz garantieren, wie hier ein wenig berührt und auch genau von der JLS
.