Я всегда считал, что Java — лаконичный и красивый (в плане концепции) язык с четкой структурой, позволяющей расширять эту структуру и на всевозможные фреймворки, там самым помогающая привнести порядок и в код конечного программиста. И, прежде всего, я считал, что java — это 100% ОО язык! Но недавно мне попался код, после которого я вечер ходил возмущался. Код совершенно несложный для понимания даже людей несведующий в java.
Допустим у нас есть класс А в некотором пакете:
Как видно поле x является защищенным и, согласно доке от sun, это поле не видимо ни в подклассах А, ни в пакете test, ни тем более в других пакетах. Поэтому у нас есть все основания считатать, что метод test() возвращает всегда число 33. Более того, мы бы могли использовать это предположение в своем коде, завязав на этом какую-либо логику.
Далее, имеем класс в любом другом пакете (но в пределах этой же JVM):
Вот и все. Все наши предположения о инкапсуляции и неизменности поля А.х развеяны. Метод А.test() теперь возвращает число 34 (и, если мы завязали на этом какую-нибудь логику, то наш код вряд ли теперь будет работать корректно). И даже может показаться, что нарушена одна из трех заповедей ООП — инкапсуляция. Во всем виновенпрограммист пакет java.lang.reflect. Этот пакет предоставляет возможности для работы с объектами на этапе выполнения программы. Т.к. практически все классы этого объекта работают с динамическими структурами, то он довольно медленно работает и должен использоваться лишь в исключительных случаях. Однако возможность его применения остается и нарушение инкапсуляции налицо.
Впоследствии, покапавшись с этим пакетом, я нашел, что за соблюдение безопасности и доступа отвечает специальный класс SecurityManager и, если его запустить, то все становится на свои места. Если нашему классу А добавить статический инициализатор:
То финт ушам, какой получился в предыдущем примере, уже не пройдет. Т.ч. все в порядке, Java по-прежнему ОО язык :) Единственное, для чего я написал этот пост — предупредить (это не сигнал к действию, просто нужно это тоже иметь в виду) всех явистов:
РАЗРАБОТЧИК, БДИ!
При отсутствии SecurityManager на этапе выполнения в твой класс может залезть кто-угодно и изменить что-угодно!
Допустим у нас есть класс А в некотором пакете:
package test;
public class A {
private int x = 33;
public void test(){
System.out.println(x);
}
}
Как видно поле x является защищенным и, согласно доке от sun, это поле не видимо ни в подклассах А, ни в пакете test, ни тем более в других пакетах. Поэтому у нас есть все основания считатать, что метод test() возвращает всегда число 33. Более того, мы бы могли использовать это предположение в своем коде, завязав на этом какую-либо логику.
Далее, имеем класс в любом другом пакете (но в пределах этой же JVM):
package access;
public class X {
public void getAccess() throws Exception{
A a = new A();
Field x = a.getClass().getDeclaredField("x");
x.setAccessible(true);
x.setInt(a, x.getInt(a)+1);
System.out.print("protected field: ");
a.test();
}
}
Вот и все. Все наши предположения о инкапсуляции и неизменности поля А.х развеяны. Метод А.test() теперь возвращает число 34 (и, если мы завязали на этом какую-нибудь логику, то наш код вряд ли теперь будет работать корректно). И даже может показаться, что нарушена одна из трех заповедей ООП — инкапсуляция. Во всем виновен
Впоследствии, покапавшись с этим пакетом, я нашел, что за соблюдение безопасности и доступа отвечает специальный класс SecurityManager и, если его запустить, то все становится на свои места. Если нашему классу А добавить статический инициализатор:
public class A {
static{
if(System.getSecurityManager()==null)
System.setSecurityManager(new SecurityManager());
}
То финт ушам, какой получился в предыдущем примере, уже не пройдет. Т.ч. все в порядке, Java по-прежнему ОО язык :) Единственное, для чего я написал этот пост — предупредить (это не сигнал к действию, просто нужно это тоже иметь в виду) всех явистов:
РАЗРАБОТЧИК, БДИ!
При отсутствии SecurityManager на этапе выполнения в твой класс может залезть кто-угодно и изменить что-угодно!