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

У меня есть вложенный (статический) класс с полем private и методом установки для этого поля.

public class Outer{
    private static class Inner{ // List node
        private String fieldA;

        // ...other members...

        public void setA(String fieldA)
        {
            //.. do importent stuff before setting fieldA
            this.fieldA = fieldA;
        }
    }
}

Теперь у нас возникла ошибка, потому что доступ к полю A осуществляется напрямую (а не методом установки setA) классом Outer, хотя поле fieldA является частным. Как я могу заставить разработчиков использовать метод установки вместо прямого доступа к полю?

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


person thersch    schedule 18.11.2014    source источник
comment
Должен ли он должен быть вложенным? Я думаю, что это, вероятно, проблема - поскольку он вложен, внешний код может получить доступ к переменной. Если вы удалите этот вложенный класс, он будет вести себя так, как вы этого хотите.   -  person Tim Hobbs    schedule 18.11.2014
comment
Я мог бы выдвинуть его. Но тогда все остальные классы в этом пакете увидят этот (бывший вложенный) класс. Но вложенный класс используется только внешним классом.   -  person thersch    schedule 18.11.2014


Ответы (1)


Если класс нельзя перемещать за пределы Outer, вы должны определить интерфейс для Inner и использовать только его. Если у вас всего несколько экземпляров и это не критическая точка производительности вашего приложения, вы можете просто создать анонимные реализации этого интерфейса. Класс больше не статичен, но, по крайней мере, это короткое и читаемое решение.

private static interface Inner {
    void setA(String a);
}

private  static Inner createInner() {
    return new Inner() {
        private String a;

        @Override
        public void setA(String a) {
            this.a = a;
        }
    };
}

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

Это выглядит немного странно, но вы можете переместить реализацию в интерфейс, как в следующем примере — это не мешает никому использовать Inner.InnerImpl, но должно подразумевать, что класс InnerImpl принадлежит Inner и не используется напрямую.

public class Outer{

    private static interface Inner {

        static class InnerImpl implements Inner {

            private String a;

            @Override
            public void setA(String a) {
                this.a = a;
            }
        }

        void setA(String a);

    }

    // either instantiate directly or again wrap it in a `createInner()` method 
    // Inner inner = new Inner.InnerImpl();
}

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

private static class Inner {

    private String _a;

    public void setA(String a) {
        this._a = a;
    }

}
person kapex    schedule 18.11.2014
comment
+1 за ваше творчество. Все предложения - хорошие идеи. Но лучше всего последний. Не так безопасно, как другие, но так хорошо читается. Спасибо. - person thersch; 18.11.2014
comment
Да я тоже так думаю. Если это будет слишком сложно, это только создаст больше путаницы. Будь проще, тупица :) - person kapex; 18.11.2014