Подтвердить что ты не робот

Публичная статическая конечная переменная в импортированном классе java

Я случайно столкнулся с кодом Java на своем рабочем месте. Здесь сценарий: Есть 2 класса - ClassA и ClassB.

ClassA не содержит ничего, кроме 4 открытых статических окончательных значений строки внутри него. Его цель - использовать такие значения, как ClassA.variable (не спрашивайте меня, почему, это не мой код).

ClassB импортирует ClassA. Я отредактировал строковые значения в ClassA и скомпилировал его. Когда я побежал ClassB, я мог видеть, что он использовал старые значения, а не новые значения. Мне пришлось перекомпилировать ClassB, чтобы использовать новые значения из ClassA! (Мне пришлось перекомпилировать другие классы, которые импортируют ClassA!)

Это только из-за JDK 1.6, или я должен был раньше знать, чтобы перекомпилировать ClassB тоже! Просветите меня.:)

4b9b3361

Ответ 1

Если значения переменных final из класса ClassA являются константами времени компиляции, компилятор мог бы вставить их в классы с помощью ClassA вместо генерации ссылки во время выполнения. Я думаю, вот что произошло в том случае, когда вы описали.

Пример:

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);
    }
}

В этом примере компилятор, скорее всего, включит значение FOO в код, сгенерированный для Consumer, вместо генерации эквивалентной ссылки во время выполнения. Если значение FOO изменится позже, вам придется перекомпилировать Consumer, чтобы использовать новое значение.

Это оптимизация, которая имеет несколько преимуществ в отношении эффективности и скорости скомпилированной программы. Например, вложение значения может позволить дальнейшие оптимизации в выражениях, которые его используют, например:

int x = Flags.FOO * 10;

В этом примере вложение значения (здесь: 1) позволяет компилятору заметить, что умножение не имеет значения и может быть опущено все вместе.

Ответ 2

Это проблема двоичной совместимости. Ссылки на постоянные поля разрешаются во время компиляции. Поведение, которое вы видите, является правильным; если вы измените значения в классе A, вам придется повторно скомпилировать клиента (класс B). Чтобы избежать таких проблем, рассмотрите возможность добавления констант с использованием типа enum, представленного в версии Java 5.0.

Ответ 3

Почему вы пытаетесь скомпилировать классы отдельно?

Используйте систему сборки, такую ​​как maven или ant, или просто позвольте вашей среде IDE делать это.

Единственное, что нужно сделать, это перекомпилировать каждую java, которая зависит от класса java, который изменился до тех пор, пока каждый класс, который можно было бы выполнить, был повторно скомпилирован.

Ответ 4

Если вы не используете значения в коммутаторе, вы можете сделать это вместо:

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

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

тогда компилятор больше не будет жестко кодировать значения в других классах, которые их используют.

Ответ 5

Предположим, что ClassA выглядит так:

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

Если вы перекомпилируете его, ClassB продолжит использовать старые значения. Я думаю, это может зависеть от компилятора, но я думаю, что это типичное поведение. Если вы не хотите перекомпилировать ClassB каждый раз в константе в изменениях ClassA, вам нужно будет сделать что-то вроде этого:

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; }
}

В настоящее время javac не хочет встраивать константы. Вместо этого он будет вызывать метод CONST (int), когда запускается статический инициализатор ClassA.