Статические методы Java, обращающиеся к закрытым переменным

У меня создалось впечатление, что частные нестатические переменные могут быть доступны только с помощью методов, называемых объектом, в котором находятся переменные, но это не так. Может кто-нибудь объяснить причину, почему следующие компиляции и работает?

public class Sandbox {
    private String _privateString = "unmodified";
    public static void setPrivateString(String str, Sandbox s) {
        s._privateString = str;
    }
    public String toString()
    {
        return _privateString;
    }

    public static void main(String[] args) {
        Sandbox s = new Sandbox();
        setPrivateString("modified", s);
        System.out.println(s);
    }
}

Вывод:

modified

EDIT: То же самое верно в С#.

Ответ 1

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

Причина в том, что класс считается автономным телом логики (то есть конкретной реализацией), поэтому имеет смысл, что конфиденциальность содержится внутри класса; нет никаких оснований исключать статические методы из этого права доступа, поскольку они также являются частью конкретной реализации, предоставляемой классом.

Ответ 2

Правило простое:

Методы-члены класса могут получать доступ и изменять частные члены одного и того же класса независимо от их видимости.

Ответ 3

Как упоминалось в некоторых других сообщениях, система видимости Java является основанной на классе, а не объектной.

Обратите внимание, что это используется в компиляторе: когда у вас есть вложенные классы и вы получаете доступ к закрытому полю внешнего класса, создается открытый синтетический статический метод, позволяющий получить доступ. Обычно он называется "доступ $0" и т.д. Вы можете создать байт-код, который нарушает инкапсуляцию без Reflection API, используя эти синтетические методы. Вы также можете получить к ним доступ из API Reflection, не предоставляя доступ к закрытым членам. Многие сумасшедшие вещи можно сделать...

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

... Хьювер, конечному программисту, как правило, не нужно знать эту деталь. IDE не включают синтетические методы в завершение кода, и я надеюсь, что компиляторы (кроме Jasmin) не позволяют вам использовать его. Поэтому, если вы не генерируете байт-код и не используете Reflection API, и игнорируете эти методы в stacktrace, вам, вероятно, не нужно знать эту деталь.

Ответ 4

Кажется, вы сбиваете с толку visibility с помощью scope. Переменные экземпляра находятся в области экземпляра, поэтому они не могут быть доступны в статическом методе напрямую, но только с квалификатором эталонного экземпляра: s._privateString в вашем случае.

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

Ответ 5

Ваш код скомпилирован, потому что внутри setPrivateString (String str, Sandbox s) вы обращаетесь к закрытой переменной _privateString по ссылочной переменной s.

Нестатический член может получить доступ только к переменной экземпляра из статического API.

Проверьте этот код

public class Sandbox {

    public static void main(String[] args) {
        Sandbox s = new Sandbox();
        // testAccess();// If you uncomment this line you will get compile time error
        s.testAccess();//can only access in this way
    }

    private void testAccess() {
        System.out.println("can only access by instance variable from static method");
    }
}