Имена enum интернированы в Java?


имена enum интернированы в Java?

т. е. гарантируется ли, что enum1.name() == enum2.name() в случае с тем же именем? И безопасно ли сравнивать enum.name() к строке, которая гарантированно будет интернирована.

4 55

4 ответа:

Хотя нет явной гарантии этого, конечный результат обязательно будет таким, что сравнение всегда будет успешным для enum константы с одинаковыми именами:

enum A {enum1};
enum B {enum1};
System.out.println(A.enum1.name() == B.enum1.name()); // Prints "true"

причина этого в том, что компилятор Java создает подклассы Enum таким образом, что они в конечном итоге вызов Enumединственный защищенный конструктор, передающий ему имя enum значение:

protected Enum(String name, int ordinal);

имя встраивается в сгенерированный код в виде строки буквальный. Согласно String документация

все литеральные строки и строковые константные выражения интернируются.

это означает неявную гарантию успешного выполнения вашего выражения, когда имена enum константы идентичны. Однако я бы не стал полагаться на такое поведение, а использовал equals(...) вместо этого, потому что любой читающий мой код будет почесывать голову, думая, что я сделал ошибку.

нет.

ответ Dasblinkenlight это лучший ответ, который мы имеем до сих пор. Там он говорит:

причина этого заключается в том, что компилятор Java создает подклассы Enum таким образом, что они в конечном итоге вызов Enum's единственной защитой конструктор, передавая ему имя enum стоимостью

и там их интернируют, потому что они строковые константы.

а, в JLS, 8.9.2, Перечисление Тела Объявления есть:

на практике, компилятор, скорее всего, зеркало Enum тип объявления String и int параметры в конструкторе по умолчанию Ан enum тип. Однако эти параметры не указаны, как "неявно объявлено" потому что различные компиляторы не нужно согласитесь на форму конструктора по умолчанию. Только компилятор Ан enum тип знает, как создавать enum константы; другие компиляторы могут просто полагаться на неявно объявленный public static поля из enum тип (§8.9.3) без учета того, как эти поля были инициализированы.

(выделено мной)

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

таким образом, это вполне возможно для меня, чтобы написать правильный и JLS-совместимый Java-компилятор, который не будет каким-то образом интернировать имена, вероятно, не имея имен, хранящихся в виде литералов. Да, он будет делать это нарочно, чтобы злонамеренно нарушить ваш код, но это будет правильное поведение в спецификации.


практически сказал, Да.

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

пожалуйста, не полагайтесь на такое неопределенное и специфичное для реализации поведение. Если вам действительно нужно, напишите для него модульный тест. И поставить assert в коде, и много объяснять. Измерьте, действительно ли ваш подход будет что-то делать.

рассмотрим цикл над и intern() их вручную перед их использованием. Таким образом, это будет сразу же ясно, что вы делаете. это не работает надежно. Смотрите комментарии.

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

Это, как говорится, да .метод equals возвращает true, если они одинаковы.

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

в документации Oracle о Enum говорится (первая строка):

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

если это правда, то, да, ваш enum1.name() == enum2.name() гарантированно будет истинно, если имена те же самые.

также, в методе name() javadoc:

public final String name() Возвращает имя этой константы перечисления, точно как объявлено в ее объявлении перечисления. Большинство программистов должны использовать метод toString() вместо этого, так как метод toString может возвращать более удобное имя. Этот метод предназначен в первую очередь для использования в специализированных ситуациях, где корректность зависит от получения точного названия, которое не будет меняться от выпуска к выпуску. Возвращает: имя этой константы перечисления

например, если у вас было два перечисления, Days и MyDays, где Воскресенье является общим значением, == между значениями объекта перечисления, в воскресенье будет возвращать значение true, как вы сравниваете две строки - см. в рабочем примере в http://ideone.com/U1Bmcw.

/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
    public static enum Day{SUNDAY, MONDAY, TUESDAY};
    public static enum MyDays{SUNDAY};

    public static void main (String[] args) throws java.lang.Exception
    {
        MyDays m = Ideone.MyDays.SUNDAY;
        Day d = Ideone.Day.SUNDAY;

        System.out.println(d.name() == m.name());
    }
}