Все ли константы времени компиляции встроены? - PullRequest
22 голосов
/ 18 декабря 2008

Допустим, у меня есть такой класс:

class ApplicationDefs{
public static final String configOption1 = "some option";
public static final String configOption2 = "some other option";
public static final String configOption3 = "yet another option";
}

Многие другие классы в моем приложении используют эти опции. Теперь я хочу изменить один из вариантов и развернуть только скомпилированный класс. Но если эти поля встроены в потребительские классы, это становится невозможным, верно?

Есть ли возможность отключить встраивание констант времени компиляции?

Ответы [ 6 ]

27 голосов
/ 26 февраля 2010

Вы можете использовать String.intern (), чтобы получить желаемый эффект, но вам следует прокомментировать ваш код, потому что об этом мало кто знает. т.е.

public static final String configOption1 = "some option".intern();

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

В качестве альтернативы вы всегда можете сделать

public static final String configOption1 = "some option".toString();

однако это не будет использовать скомпилированную строку intern'd, она создаст новую для старого поколения. Не большое дело, и может быть легче читать. В любом случае, поскольку это немного странно, вы должны прокомментировать код, чтобы сообщить тем, кто его поддерживает, что вы делаете.

Edit: Нашел другую ссылку SO, которая дает ссылки на JLS, для получения дополнительной информации об этом. Когда использовать intern () для строковых литералов

10 голосов
/ 18 декабря 2008

Нет, боюсь, это часть JLS. Это кратко затронуто в Java Puzzlers, но у меня нет своей копии.

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

Ссылка: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#5313

7 голосов
/ 18 декабря 2008

Нет. Вы можете заменить их статическим вызовом метода, например:

class ApplicationDefs {

    public static String configOption1() { return "some option"; }

}

Конечно, это не красиво, но будет соответствовать вашим требованиям. :)

7 голосов
/ 18 декабря 2008

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

Однако настоятельно рекомендуется, чтобы, если это действительно какая-то конфигурация, которую вы пытаетесь выполнить, вам следует перейти к более управляемому способу, чем константы в некотором файле класса.

6 голосов
/ 18 декабря 2008

Вы можете запретить встраивание, задав свои постоянные некомпилируемые постоянные времени ...

Например, null не является константой времени компиляции. Любое выражение, включающее некомпилированную постоянную времени, не является постоянной времени компиляции, хотя javac может выполнять свертывание констант в модуле компиляции.

public static final String configOption1 = null!=null?"": "some option";
0 голосов
/ 18 декабря 2008

Здесь нет ничего, что говорит, что эти значения должны быть встроены. Вы просто объявляете некоторых public, static участников. Эти другие классы используют значения этих членов. Никакого встраивания не требуется. Даже ключевое слово final

Но по причинам производительности некоторые JVM могут встроить эти значения в другие классы. Это оптимизация. Никакая оптимизация не должна изменить поведение программы. Поэтому, если вы измените определение этих членов, JVM должна un-inline предыдущие значения.

Вот почему нет способа отключить встраивание. Либо JVM не встроена и проблем нет, либо, если она встроена, JVM гарантирует отключение.

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

...