Подтвердить что ты не робот

Невозможно сделать статическую ссылку на нестатический элемент поля Variable с приватной переменной

Я создал перечисление с одной переменной частного члена. Когда я пытаюсь получить доступ к переменной-члену, состояния компиляции "Не удается создать статическую ссылку на нестатический элемент поля Variable".

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

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

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);

}
4b9b3361

Ответ 1

Сообщение об ошибке запутывается.

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

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

    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;
}

Ответ 2

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

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

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

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

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

Или же

        EnumWithAbstractMethodAndMembers innerThis = this;
        return innerThis.memberVariable + value;

Ответ 3

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

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

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

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