Константные выражения Java и исключение кода

Как обсуждалось здесь, javac и другие компиляторы Java могут предоставлять возможности удаления кода для if- заявления, где условие является "выражением константы".

Как это повлияет, если мой код использует константное выражение, которое зависит от других константных выражений, определенных в разных пакетах?

Например, допустим, у меня есть следующие классы в соответствующих указанных пакетах:

package foo;

public class Foo {
    public static final boolean CONDITION = false;
}

а также

package bar;

import foo.Foo;

public class Bar {
    public void test() {
        if (Foo.CONDITION) {
            System.out.println("This line of code could be eliminated.");
        } else {
            System.out.println("This line of code will be executed.");
        }
    }
}

Понятно, если foo-package загружается во время выполнения из внешнего jar-файла, компилятор не может технически просто предполагать, что Foo.CONDITION будет ложным и не должно устранять trueветвь if-заявление.

Тогда как, если Foo а также Bar были на самом деле в одной упаковке, true-branch обязательно должен быть исключен (если компилятор вообще поддерживает удаление кода).

Не совсем уверен, как лучше сформулировать этот вопрос, но: как "близко" делает Foo нужно быть Bar для постоянного выражения в Foo также считается постоянным в Bar? Должны ли они быть в одном файле? тот же пакет? тот же самый jar-файл? или это вообще не имеет значения (т.е. компилятор всегда учитывает Foo.CONDITION в качестве константы и использовать значение, найденное в пути сборки во время компиляции)?

2 ответа

Решение

Так как это часть публичной "подписи" ссылочного класса, она считается постоянной. По сути, идея заключается в том, что final означает окончательный, и если вы измените его, это ваша вина.

Это похоже на фактические сигнатуры методов ссылочных классов, также принимаемые как есть во время компиляции. Вот почему, если вы компилируете свой код для одной версии библиотеки и запускаете ее для другой, вы можете получить NoSuchMethodError,

Обновление: на самом деле JLS дает еще более сильную гарантию:

Если поле является константной переменной (§4.12.4), то удаление ключевого слова final или изменение его значения не нарушит совместимость с уже существующими двоичными файлами, заставив их не запускаться, но они не увидят никакого нового значения для использования. поля, если они не перекомпилированы. Это верно, даже если само использование не является константным выражением времени компиляции (§15.28).

Этот результат является побочным эффектом решения поддержать условную компиляцию, как обсуждалось в конце §14.21.

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

Согласно Спецификации языка Java, любое статическое конечное поле, инициализированное выражением, которое может быть оценено во время компиляции, должно быть скомпилировано в байтовый код, который "вставляет" значение поля. То есть динамическая ссылка не будет присутствовать внутри класса Main, что говорит ему получить значение для A от InterfaceA во время выполнения. Вместо этого литерал 1 будет напрямую скомпилирован в Main.main().

Другие вопросы по тегам