Java Enum доступ к закрытой переменной экземпляра - PullRequest
15 голосов
/ 27 февраля 2012

Рассмотрим пример:

enum SomeEnum {
    VALUE1("value1"),
    VALUE2("value2"),
    VALUE3("value3")
    ;
    private String value;

    private SomeEnum(final String value) {
        this.value = value;
    }

    //toString
    public String toString() {
        return value;
    }
}

Почему мы можем это сделать (и значение действительно изменяется)?

SomeEnum.VALUE1.value = "Value4";
System.out.println(SomeEnum.VALUE1);

Разве эти перечисления не являются неявно статическими и окончательными ? Кроме того, поскольку value равно private, почему я могу получить к нему доступ за пределами других классов?

Ответы [ 6 ]

21 голосов
/ 27 февраля 2012

Никто, кажется, не обращался к частному аспекту.Я предполагаю, что вы получаете доступ к закрытому полю из содержащего типа - что ваше перечисление на самом деле вложенного типа, например:

class Test
{
    static void Main() {
        // Entirely valid
        SomeEnum.VALUE1.value = "x";
    }

    enum SomeEnum {
        VALUE1("value1");

        private String value;

        private SomeEnum(final String value) {
            this.value = value;
        }
    }
}

Это вполне законно и нормально - выможет всегда обращаться к закрытым членам вложенного типа из содержащего типа.

Если вы сделаете перечисление типом верхнего уровня, вы не увидите этого.

Что касается изменения значений - как все говорили, VALUE1 неявно статичен и окончателен, но это не мешает вам изменить VALUE1.value.Опять же, это полностью соответствует тому, как Java работает в других местах - если у вас есть статическое поле типа List, вы все равно можете добавить в него записи, потому что это не изменяет само поле .

Если вы хотите сделать SomeEnum должным образом неизменным, сделайте поле value final.

5 голосов
/ 27 февраля 2012

Вы не можете сделать

SomeEnum.VALUE1 = "Value4";
System.out.println(SomeEnum.VALUE1);

но вы можете сделать

SomeEnum.VALUE1.value = "Value4";
System.out.println(SomeEnum.VALUE1);

и value действительно изменяются, но не статический финал VALUE1 .

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

Вы можете получить доступ к закрытому полю во внешнем / внутреннем классе, но я не могу найти пример, где вы можете получить к нему доступ из другого класса (например, в том же пакете).

2 голосов
/ 27 февраля 2012

Разве эти перечисления не являются неявно статическими и final ?

Экземпляры Enum имеют эти черты.Но никто не сказал, что эти случаи неизменны как Integer или String.Таким образом, вы можете изменить значения.

Это не значит, что это рекомендуемая практика!Это не так.

Редактировать

Чтобы объяснить немного больше:

"Enum неявно статично" означает:

enum Foo { FOO };

Здесь FOO является статическим, хотя синтаксис Java normal предполагает, что FOO - это переменная экземпляра, ошибочно названная как константа.Вы также получаете к нему доступ как к статической переменной.

«Enum implicitly final» означает:

enum Foo { FOO, BAR };
Foo.FOO = Foo.BAR;

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

«Enum not implicitly immutable» означает: Foo.FOO даст вам объект.Стандартный объект.Если объект допускает модификации собственного контента - так и будет.Это не запрещено.

2 голосов
/ 27 февраля 2012

Разве эти перечисления не являются неявно статическими и окончательными?

Неа. Члены enum-экземпляров, такие как value в вашем примере, могут быть изменяемыми.

(Ссылки на экземпляры (SomeEnum.VALUE1 и т. Д. В вашем примере) являются окончательными и статичными.

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

Вы не можете. enum - это «класс» с перечислимым числом экземпляров. Вот и все.

VALUE1 в данном случае является экземпляром «класса» SomeEnum, поэтому SomeEnum.VALUE1.value является обычным полем, как и любое другое.


Когда вы делаете

System.out.println(SomeEnum.VALUE1);

вы вызываете SomeEnum.VALUE1.toString, который обращается к полю value. Вы не получаете доступ к полю value немедленно.

// Not possible since field is private.
System.out.println(SomeEnum.VALUE1.value);
1 голос
/ 27 февраля 2012

SomeEnum.VALUE1 = "Value4" ... на самом деле не работает.

Более важно, VALUE1 всегда будет равняться только VALUE1, а не VALUE2 или VALUE3, независимо от значения его элемента.

1 голос
/ 27 февраля 2012

Перечисления (VALUE1, VALUE2 и VALUE3) являются статическими и окончательными. Это три экземпляра типа SomeEnum, и мы не можем их изменить (например, удалив VALUE1 из перечисления или добавив VALUE4 во время выполнения).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...