Чтение онлайн

на главную - закладки

Жанры

Философия Java3

Эккель Брюс

Шрифт:

Название. SnowRemova1 Robot NullRobot Модель: SnowRemovalRobot NullRobot *///.-

Каждый раз, когда вам требуется объект Robot с неопределенным состоянием, вы вызываете newNuURobotQ и передаете тип Robot, для которого создается

посредник. Посредник выполняет требования о поддержке интерфейсов Robot и Null, а также предоставляет имя опосредованного типа.

Интерфейсы и информация о типах

Одной из важных целей ключевого слова interface является изоляция компонентов и сокращение привязок. Использование интерфейсов

вроде бы позволяет добиться этой цели, однако RTTI позволяет обойти ограничения — интерфейсы не обеспечивают стопроцентной изоляции. Начнем следующий пример с интерфейса:

//: typeinfo/interfacea/A.java package typeinfo.interfacea;

public interface A {

void f; } ///:-

Затем интерфейс реализуется, и выясняется, что можно «в обход» добраться до фактического типа реализации:

//• typei nfo/1nterfaceVi olati on.java // Интерфейс можно обойти import typeinfo.interfacea.*;

class В implements A { public void f {} public void g {}

}

public class InterfaceViolation {

public static void main(String[] args) { A a = new BO; a.fO;

// a.gO; // Ошибка компиляции System.out.pri ntln(a.getClass.getName); if(a instanceof B) { В b = (B)a; b.gO;

}

}

} /* Output: В

*///:-

Используя RTTI, мы выясняем, что объект а реализован в форме В. Преобразование к типу В позволяет вызвать метод, не входящий в интерфейс А.

Все это абсолютно законно и допустимо, но, скорее всего, вы предпочли бы оградить клиентских программистов от подобных выходок. Казалось бы, ключевое слово interaface должно защищать вас, но на самом деле этого не происходит, а факт использования В для реализации А становится известен любому желающему.

Одно из возможных решений: просто скажите программистам, что если они будут использовать фактический класс вместо интерфейса, то пускай сами разбираются со всеми возникающими проблемами. Вероятно, во многих случаях этого достаточно, но если «вероятно» вас не устраивает — можно применить более жесткие меры.

Проще всего установить для реализации пакетный уровень доступа, чтобы она оставалась невидимой для клиентов за пределами пакета:

//. typeinfo/packageaccess/HiddenC.java package typeinfo.packageaccess; import typeinfo interfacea.*; import static net mindview util.Print *.

class С implements A {

public void f { print("public С f"), } public void g { printCpublic С g"); } void u { print ("package C.uO"); } protected void v { print("protected С v"). } private void wO { printC'private C.wO"), }

}

public class HiddenC {

public static A makeAO { return new CO; } } ///:-

Единственная открытая (public) часть пакета, HiddenC, выдает интерфейс А при вызове. Интересно отметить, что, даже если makeA будет возвращать С, за пределами пакета все равно удастся использовать только А, потому что имя С недоступно.

Попытка нисходящего преобразования к С тоже завершается

неудачей:

II: typeinfo/Hiddenlmplementation.java // Пакетный доступ тоже можно обойти import typeinfo.interfacea.*; import typeinfo.packageaccess *; import java.lang.reflect *;

public class Hiddenlmplementation {

public static void main(String[] args) throws Exception { . A a = Hi ddenC. makeAO; a.fO;

System.out.pri ntin(a.getClass О.getName); // Ошибка компиляции, символическое имя 'С' не найдено /* if(a instanceof С) { С с = (С)а; с.дО;

} */

// Однако рефлексия позволяет вызвать д: callHiddenMethod(a, "д"); // ... И даже еще менее доступные методы! callHiddenMethod(a, "и"); са11 Hi ddenMethod С а, "v"); callHiddenMethod(a, "w");

}

static void call HiddenMethod(Object a, String methodName)

throws Exception { продолжение &

Method g = a getClassO getDeclaredMethod(methodName), g.setAccessible(true). g.invoke(a),

}

} /* Output public C.fO

typeinfo.packageaccess С public С gO package С uO protected C.vO private C.wO */// ~

Как видите, рефлексия позволяет вызвать все методы, даже приватные! Зная имя метода, можно вызвать setAccessible(true) для объекта Method, чтобы сделать возможным его вызов, как видно из реализации caUHiddenMethod.

Можно подумать, что проблема решается распространением только откомпилированного кода, но и это не так. Достаточно запустить javap — декомпилятор, входящий в JDK. Командная строка выглядит так:

javap -private С

Флаг -private означает, что при выводе должны отображаться все члены, даже приватные. Таким образом, любой желающий сможет получить имена и сигнатуры приватных методов и вызвать их.

А если реализовать интерфейс в виде приватного внутреннего класса? Вот как это выглядит:

//: typeinfo/Innerlmplementation java

// Приватные внутренние классы не скрываются от рефлексии

import typeinfo interfacea *;

import static net mindview.util Print.*;

class InnerA {

private static class С implements A {

public void f { printC'public C.fO"); } public void gO { printC'public C.gO"); } void uO { print("package C.uO"); } protected void v { print ("protected C.vO"), } private void w { printC'private С w"). }

}

public static A makeAO { return new CO; }

}

public class Innerlmplementation {

public static void main(String[] args) throws Exception { A a = InnerA makeAO; a f.

System out. pri ntl n(a getClassO .getNameO); // Рефлексия все равно позволяет добраться до приватного класса: Hiddenlmplementation callHiddenMethod(a. "g"); HiddenImplementation.callHiddenMethod(a, "u"), HiddenImplementation.callHiddenMethod(a, "v"), HiddenImplementation.callHiddenMethod(a. "w");

Поделиться:
Популярные книги

Барон играет по своим правилам

Ренгач Евгений
5. Закон сильного
Фантастика:
попаданцы
аниме
фэнтези
фантастика: прочее
5.00
рейтинг книги
Барон играет по своим правилам

Сердце Дракона. нейросеть в мире боевых искусств (главы 1-650)

Клеванский Кирилл Сергеевич
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.51
рейтинг книги
Сердце Дракона. нейросеть в мире боевых искусств (главы 1-650)

Герцогиня в ссылке

Нова Юлия
2. Магия стихий
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Герцогиня в ссылке

Ну привет, заучка...

Зайцева Мария
Любовные романы:
эро литература
короткие любовные романы
8.30
рейтинг книги
Ну привет, заучка...

На Ларэде

Кронос Александр
3. Лэрн
Фантастика:
фэнтези
героическая фантастика
стимпанк
5.00
рейтинг книги
На Ларэде

Сердце Дракона. Том 12

Клеванский Кирилл Сергеевич
12. Сердце дракона
Фантастика:
фэнтези
героическая фантастика
боевая фантастика
7.29
рейтинг книги
Сердце Дракона. Том 12

Истинная поневоле, или Сирота в Академии Драконов

Найт Алекс
3. Академия Драконов, или Девушки с секретом
Любовные романы:
любовно-фантастические романы
6.37
рейтинг книги
Истинная поневоле, или Сирота в Академии Драконов

Кодекс Охотника. Книга VI

Винокуров Юрий
6. Кодекс Охотника
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Кодекс Охотника. Книга VI

Гардемарин Ее Величества. Инкарнация

Уленгов Юрий
1. Гардемарин ее величества
Фантастика:
городское фэнтези
попаданцы
альтернативная история
аниме
фантастика: прочее
5.00
рейтинг книги
Гардемарин Ее Величества. Инкарнация

Сама себе хозяйка

Красовская Марианна
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Сама себе хозяйка

Душелов. Том 3

Faded Emory
3. Внутренние демоны
Фантастика:
альтернативная история
аниме
фэнтези
ранобэ
хентай
5.00
рейтинг книги
Душелов. Том 3

Газлайтер. Том 10

Володин Григорий
10. История Телепата
Фантастика:
боевая фантастика
5.00
рейтинг книги
Газлайтер. Том 10

Стеллар. Заклинатель

Прокофьев Роман Юрьевич
3. Стеллар
Фантастика:
боевая фантастика
8.40
рейтинг книги
Стеллар. Заклинатель

Возвышение Меркурия. Книга 5

Кронос Александр
5. Меркурий
Фантастика:
боевая фантастика
попаданцы
аниме
5.00
рейтинг книги
Возвышение Меркурия. Книга 5