Невозможно сделать статическую ссылку на нестатическое поле memberVariable с закрытой переменной - PullRequest
18 голосов
/ 09 декабря 2011

Я создал enum с одной закрытой переменной-членом.Когда я пытаюсь получить доступ к переменной-члену, компиляция заявляет: «Невозможно сделать статическую ссылку на нестатическое поле memberVariable».

Если переменная не является частной (например, защищенной или защищенной пакетом), она компилируется нормально.Я не понимаю, как область действия переменной связана с типом (статическим, не статическим) реализованной абстрактной функции.

Может ли кто-нибудь просветить меня?

public enum EnumWithAbstractMethodAndMembers {
    TheOneAndOnly(1) {
        @Override
        public int addValue(final int value) {
            return memberVariable + value;
        }
    };

    private final int memberVariable;

    private EnumWithAbstractMethodAndMembers(final int memberVariable) {
        this.memberVariable = memberVariable;
    }

    abstract int addValue(int value);

}

Ответы [ 3 ]

20 голосов
/ 09 декабря 2011

Сообщение об ошибке сбивает с толку.

Проблема в том, что когда вы даете код значения перечисления, вы создаете анонимный подкласс перечисления. (Его класс будет EnumWithAbstractMethodAndMembers$1). Подкласс не может получить доступ к закрытым членам своего суперкласса, однако вложенные классы могут через сгенерированный метод доступа. Вы должны иметь доступ к закрытому полю, и сообщение об ошибке, которое оно выдает, кажется неверным.

Кстати, вы можете использовать это, но вам не нужно ИМХО.

    public int addValue(final int value) {
        return super.memberVariable + value;
    }

Вот более короткий пример, который я буду регистрировать как сообщение об ошибке в сообщении об ошибке, поскольку оно не приводит к решению проблемы.

public enum MyEnum {
    One {
        public int getMemberVariableFailes() {
            // error: non-static variable memberVariable cannot be referenced from a static context
            return memberVariable;
        }

        public int getMemberVariable2OK() {
            return memberVariable2;
        }

        public int getMemberVariableOK() {
            return super.memberVariable;
        }
    };

    private final int memberVariable = 1;
    final int memberVariable2 = 1;
}

Основываясь на отзывах Тома Хоукина, этот пример получает то же сообщение об ошибке.

public class MyNotEnum {
    // this is the static context in which the anonymous is created
    public static final MyNotEnum One = new MyNotEnum() {
        public int getMemberVariableFailes() {
            // error: non-static variable memberVariable cannot be referenced from a static context
            return memberVariable;
        }

        public int getMemberVariableOK() {
            return super.memberVariable;
        }
    };
    private final int memberVariable = 1;
}

для сравнения

public class MyNotEnum {
    public class NestedNotEnum extends MyNotEnum {
        public int getMemberVariableFailes() {
            // compiles just fine.
            return memberVariable;
        }

        public int getMemberVariableOK() {
            return super.memberVariable;
        }
    }
    private final int memberVariable = 1;
}
4 голосов
/ 09 декабря 2011

Аналогичная проблема описана в Puzzle 92 (витая пара) в Java Puzzlers Джоша Блоха и Нила Гафтера.

В перечислениях нет ничего особенного.Подойдет любой анонимный (или локальный) внутренний класс в статическом контексте.Правила таковы, что внешний класс рассматривается перед суперклассом.Это имеет большой смысл для таких классов в нестатическом контексте.Если изменение контекста на статическое изменило, какая переменная была найдена, это может привести к «путанице» во время выполнения (C ++ гораздо агрессивнее с этим типом правила).

Внутренний класс, который расширяет внешний класс, имеет доступ к частным полям экземпляра внешнего класса, через this или какой-либо другой экземпляр.

Поскольку нам разрешен доступ, нам нужночтобы как-то указать, что мы хотим пройти внутреннее это, а не внешнее это.Как указывает Питер Лори, super.member сделает.Вы также можете выбрать внутренний this, а затем использовать это выражение:

        return ((EnumWithAbstractMethodAndMembers)this).memberVariable + value;

или

        EnumWithAbstractMethodAndMembers innerThis = this;
        return innerThis.memberVariable + value;
0 голосов
/ 09 декабря 2011

Основная причина ошибки: вы пытаетесь сделать ссылку на приватную переменную (memberVariable) суперкласса из внутреннего класса реализации.

Чтобы сделать код без ошибок, выможно выполнить одно из следующих действий:

  • вы должны использовать super.memberVariable, поскольку memberVariable это не локально до TheOnlyAndOnly()
  • вы можете сделать int memberVariable публично .
  • Вы можете сделать:

    TheOneAndOnly(1) {
        int memberVariable=4;
        @Override
        public int addValue(final int value) {
            return memberVariable + value;
        }
    };
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...