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

на главную

Жанры

Философия Java3

Эккель Брюс

Шрифт:

}

public С f InnerASC public С g package С u protected С v private С w */// ~

He помогло. Как насчет анонимного класса?

// typeinfo/AnonymousImplementation java

// Анонимные внутренние классы тоже не скрыты от рефлексии

import typeinfo.interfacea *.

import static net.mindview util Print *,

class AnonymousA {

public static A makeAO { return new AO {

public void fO { printCpublic С f"), } public void gO { printCpublic С gn); } void uO { print (package C.uO"), } protected void vO { print ("protected C.vO"). } private void wО { printOprivate С wO"). }

public class AnonymousImplementation {

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

System.out.pri ntin(a.getCl ass

О.getName).

// Рефлексия все равно позволяет добраться до приватного класса.

Hiddenlmplementation callHiddenMethod(a, "g"),

Hiddenlmplementation.call HiddenMethod(a, "u");

Hi ddenlmpl ementati on callHiddenMethod(a, Y);

HiddenImplementation.callHiddenMethod(a, "w");

}

} /* Output: public C.fO AnonymousA!1 public C.gO package C.uO protected C.vO private C.wO *///•-

Похоже, не существует никакого способа предотвратить обращение и вызов методов с уровнем доступа, отличным от public, посредством рефлексии. Сказанное относится и к полям данных, даже к приватным:

//. typeinfo/ModifyingPrivateFields.java import java lang reflect *;

class WithPrivateFinalField { private int i = 1.

private final String s = "I'm totally safe";

private String s2 = "Am I safe?", продолжение &

public String toStringO {

return Hi = " + i + ", " + s + ", " + s2,

}

}

public class ModifyingPrivateFields {

public static void main(String[] args) throws Exception {

WithPrivateFinalField pf = new WithPrivateFinalField, System out println(pf);

Field f = pf getClassO getDeclaredFieldC'i"), f.setAccessible(true),

System.out.printlnC'f.getlnt(pf). " + f getlnt(pf)). f setlnt(pf. 47); System out.println(pf); f = pf getClassO getDeclaredFieldC's"). f.setAccessible(true);

System.out.printlnC'f.get(pf): " + f.get(pf)); f.set(pf. "No, you're not!"); System.out.println(pf); f = pf. getClassO. getDeclaredField("s2"); f.setAccessible(true);

System.out.printlnC'f.get(pf). " + f.get(pf)), f.set(pf, "No, you're not!"); System.out.println(pf),

}

} /* Output:

i = 1, I'm totally safe. Am I safe? f getlnt(pf): 1

i =47, I'm totally safe. Am I safe? f.get(pf): I'm totally safe i =47, I'm totally safe, Am I safe? f.get(pf): Am I safe? i =47, I'm totally safe. No, you're not! *///:-

Впрочем, final-поля защищены от изменений. Система времени выполнения спокойно воспринимает любые попытки их изменения, но при этом ничего не происходит.

В действительности все эти нарушения уровня доступа не так уж страшны. Если кто-то захочет вызывать методы, которым вы назначили приватный или пакетный доступ (тем самым ясно показывая, что вызывать их не следует), вряд ли он станет жаловаться на то, что вы изменили некоторые аспекты этих методов. С другой стороны, «черный ход» к внутреннему устройству класса позволяет решить некоторые проблемы, нерешаемые другими средствами, и в общем случае преимущества рефлексии неоспоримы.

Резюме

Динамическое определение типов (RTTI) позволяет вам получить информацию о точном типе объекта

тогда, когда у вас для него имеется лишь ссылка базового типа. Таким образом, оно открывает широкие возможности для злоупотреблений со стороны новичков, которые еще не поняли и не успели оценить всю мощь полиморфизма. У многих людей, ранее работавших с процедурными языками, возникает сильное желание разбить свою программу на множество конструкций switch при помощи RTTI. Однако при этом они лишаются всех преимуществ полиморфизма, относящихя к разработке программы в целом и ее дальнейшей поддержке. В Java рекомендуется использовать именно полиморфные методы, а к услугам RTTI следует прибегать только в крайнем случае.

Впрочем, при использовании полиморфных методов требуется полный контроль над базовым классом, поскольку в некоторой точке программы, после наследования очередного класса, вы можете обнаружить, что базовый класс не содержит нужного вам метода, и тогда RTTI вас выручит: при наследовании вы расширяете интерфейс класса, добавляя в него новые методы. Особенно верно это при использовании в качестве базовых классов библиотек, которые вы не можете изменить. Далее в своем коде в подходящий момент вы обнаруживаете новый тип и вызываете для него нужный метод. Такой подход не противоречит основам полиморфизма и расширяемости программы, так как добавление в программу нового типа не требует изменения бесчисленного множества конструкций switch. Но чтобы извлечь пользу из дополнительной функциональности нового класса, придется использовать RTTI.

Включение некоторого метода в базовый класс будет выгодно только одному производному классу, который действительно реализует его, но все остальные производные классы будут вынуждены использовать для этого метода какую-либо бесполезную «заглушку». Интерфейс базового класса «размывается» и раздражает тех, кому приходится переопределять ненужные абстрактные методы при наследовании от базового класса. Например, рассмотрим иерархию классов, представляющих музыкальные инструменты. Предположим, что вы хотите прочистить мундштуки духовых инструментов своего оркестра. Конечно, можно поместить в базовый класс Instrument (общее представление музыкального инструмента) еще один метод с lea rS pi tVa Ive (прочистка мундштуков), но тогда получится, что и у синтезатора, и у барабана есть мундштук! С помощью RTTI можно получить гораздо более верное решение данной задачи, поскольку этот метод уместно поместить в более конкретный класс (например, в класс Wind, базовый для всех духовых инструментов). Однако еще более разумным стало бы включение в класс Instrument метода preparelnstrument (подготовить инструмент к игре), который подошел бы всем инструментам без исключения. На первый взгляд можно было бы ошибочно решить, что в данном случае без RTTI не обойтись.

Наконец, иногда RTTI решает проблемы производительности. Если ваш код использует полиморфизм по всем правилам, но один из объектов чрезвычайно непродуктивно обрабатывается кодом, предназначенным для базового типа, то для этого объекта можно сделать исключение, определить его точный тип с помощью RTTI и работать с ним более производительно. Однако ни в коем случае не следует писать программы, ориентируясь только на их эффективность, как бы соблазнительно это ни было. Сначала надо получить работающую программу и только после этого решать, достаточно ли быстро она работает, и решать проблемы быстродействия, вооружившись инструментами для проверки скорости исполнения.

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

Скарамуш

Сабатини Рафаэль
1. Скарамуш
Приключения:
исторические приключения
8.58
рейтинг книги
Скарамуш

Золушка (сборник)

Макбейн Эд
Мастера остросюжетного романа
Детективы:
полицейские детективы
5.00
рейтинг книги
Золушка (сборник)

Стальные сны. Серебряный клин

Кук Глен Чарльз
Фантастика:
фэнтези
6.25
рейтинг книги
Стальные сны. Серебряный клин

Гобелены Фьонавара (сборник)

Кей Гай Гэвриел
Гобелены Фьонавара
Фантастика:
фэнтези
эпическая фантастика
6.25
рейтинг книги
Гобелены Фьонавара (сборник)

Украинский футбол: легенды, герои, скандалы в спорах «хохла» и «москаля»

Рабинер Игорь Яковлевич
Документальная литература:
публицистика
5.00
рейтинг книги
Украинский футбол: легенды, герои, скандалы в спорах «хохла» и «москаля»

Обман Инкорпорэйтед (сборник)

Дик Филип Киндред
Гиганты фантастики
Фантастика:
социально-философская фантастика
научная фантастика
6.00
рейтинг книги
Обман Инкорпорэйтед (сборник)

Неучтенный элемент. Том 12

NikL
12. Антимаг. Вне системы
Фантастика:
фэнтези
5.00
рейтинг книги
Неучтенный элемент. Том 12

Архивариус

alchoz
Проект «Поттер-Фанфикшн»
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Архивариус

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

Володин Григорий Григорьевич
19. История Телепата
Фантастика:
попаданцы
аниме
фэнтези
6.25
рейтинг книги
Газлайтер. Том 19

Зимний ветер. Катакомбы

Катаев Валентин Петрович
Проза:
современная проза
6.25
рейтинг книги
Зимний ветер. Катакомбы

Я уже князь. Книга XIX

Дрейк Сириус
19. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.50
рейтинг книги
Я уже князь. Книга XIX

Безмолвная

Герритсен Тесс
9. Джейн Риццоли и Маура Айлс
Детективы:
триллеры
8.81
рейтинг книги
Безмолвная

Я не князь. Книга XIII

Дрейк Сириус
13. Дорогой барон!
Фантастика:
юмористическое фэнтези
попаданцы
аниме
5.00
рейтинг книги
Я не князь. Книга XIII

Танцы с огнем

Робертс Нора
Любовные романы:
остросюжетные любовные романы
8.68
рейтинг книги
Танцы с огнем