Frage

Ich bin zufällig über einen Java-Code an meinem Arbeitsplatz kommen. Hier ist das Szenario:. Es gibt zwei Klassen - ClassA und ClassB

ClassA hat nichts außer 4 public static final String-Werte in seinem Inneren. Sein Zweck ist es, diese Werte wie ClassA.variable (fragen Sie mich nicht warum, es ist nicht mein Code ist) zu verwenden.

ClassB Einfuhren ClassA. Ich bearbeitete die String-Werte in ClassA und zusammengestellt. Als ich ClassB lief konnte ich sehen, daß es die alten Werte wurde mit - nicht die neuen Werte. Ich hatte ClassB neu kompilieren, um es neue Werte von ClassA verwenden zu machen! (Ich hatte andere Klassen neu zu kompilieren, die ClassA importiert!)

Ist das nur wegen JDK 1.6 oder sollte ich früher gekannt haben ClassB auch neu zu kompilieren! Kläre mich auf. :)

War es hilfreich?

Lösung

Wenn die Werte der Variablen final von Klasse ClassA sein passieren Kompilierung-Konstanten, könnte die Compiler sie in die Klassen hat mit ClassA inlined statt eine Laufzeitreferenz zu erzeugen. Ich denke, das ist, was in dem Fall passiert Sie beschrieben.

Beispiel:

public class Flags {
    public static final int FOO = 1;
    public static final int BAR = 2;
}

public class Consumer {
    public static void main(String[] args) {
         System.out.println(Flags.FOO);
    }
}

In diesem Beispiel wird der Compiler wahrscheinlich den Wert von in die FOO für Consumer erzeugten Code übernehmen anstelle der äquivalenten Laufzeitreferenz zu erzeugen. Wenn der Wert von FOO Änderungen später, müssen Sie Consumer um neu zu kompilieren, um es den neuen Wert verwenden.

Dies ist eine Optimierung, die einige Vorteile hinsichtlich Effizienz und Geschwindigkeit des Programms zusammengestellt hat. Zum Beispiel könnte den Wert inlining ermöglicht weitere Optimierungen in der Ausdrücken, die es verwendet, zum Beispiel:

int x = Flags.FOO * 10;

In diesem Beispiel inlining den Wert (hier: 1). Ermöglicht es den Compiler zu bemerken, dass die Multiplikation keinen Unterschied macht, und kann alltogether weggelassen wird

Andere Tipps

Es ist ein binäres Kompatibilitätsproblem. Verweise auf konstante Felder werden bei der Kompilierung aufgelöst. Das Verhalten, das Sie sehen, ist richtig; wenn Sie die Werte in der Klasse A ändern dann müssen Sie neu kompilieren den Client (Klasse B). Zur Vermeidung solcher Probleme sollten Sie erwägen, Konstanten einen Aufzählungstyp verwendet wird, eingeführt in Java Release 5.0.

Warum versuchen Sie die Klassen einzeln zu kompilieren?

Verwenden Sie ein Build-System wie Maven oder Ameise oder lassen Sie einfach Ihre IDE es tun.

Die einzige sichere Sache zu tun ist, jede Java neu zu kompilieren, die aus einer Java-Klasse abhängt, die bis jede Klasse hat sich geändert, die neu kompiliert wurde durchgeführt werden konnte.

Wenn Sie die Werte in einem Schalter nicht verwenden, können Sie dies tun, anstatt:

public class A
{
    public static final int FOO;
    public static final String BAR;

    static
    {
        FOO = 42;
        BAR = "Hello, World!";
    }
}

dann wird der Compiler nicht mehr schwer, die Werte in den anderen Klassen codieren, die sie verwenden.

Nehmen wir an KlasseA sieht wie folgt aus:

public class ClassA {
    public static final int FOO = 1;
    public static final int BAR = 2;
}

Wenn Sie es neu kompilieren, wird ClassB weiterhin die alten Werte verwenden. Ich denke, es auf dem Compiler abhängen könnte, aber ich denke, das ist das typische Verhalten ist. Wenn Sie möchten, eine konstante nicht neu kompilieren ClassB jedes Mal in KlasseA Änderungen, werden Sie so etwas zu tun haben:

public class ClassA {
    public static final int FOO = CONST(1);
    public static final int BAR = CONST(2);

    public static int CONST(int i) { return i; }
}

Becuase jetzt javac ist nicht bereit, die Konstanten Inline. Stattdessen wird es die CONST (int) -Methode aufrufen, wenn KlasseA statische Initialisierer ausgeführt wird.

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