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

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

Жанры

Философия 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 и работать с ним более производительно. Однако ни в коем случае не следует писать программы, ориентируясь только на их эффективность, как бы соблазнительно это ни было. Сначала надо получить работающую программу и только после этого решать, достаточно ли быстро она работает, и решать проблемы быстродействия, вооружившись инструментами для проверки скорости исполнения.

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

Идеальный мир для Лекаря 11

Сапфир Олег
11. Лекарь
Фантастика:
фэнтези
аниме
5.00
рейтинг книги
Идеальный мир для Лекаря 11

Инкарнатор

Прокофьев Роман Юрьевич
1. Стеллар
Фантастика:
боевая фантастика
рпг
7.30
рейтинг книги
Инкарнатор

Миф об идеальном мужчине

Устинова Татьяна Витальевна
Детективы:
прочие детективы
9.23
рейтинг книги
Миф об идеальном мужчине

Все ведьмы – стервы, или Ректору больше (не) наливать

Цвик Катерина Александровна
1. Все ведьмы - стервы
Фантастика:
юмористическая фантастика
5.00
рейтинг книги
Все ведьмы – стервы, или Ректору больше (не) наливать

Вечный. Книга V

Рокотов Алексей
5. Вечный
Фантастика:
боевая фантастика
попаданцы
рпг
5.00
рейтинг книги
Вечный. Книга V

Надуй щеки!

Вишневский Сергей Викторович
1. Чеболь за партой
Фантастика:
попаданцы
дорама
5.00
рейтинг книги
Надуй щеки!

Командир штрафбата

Корчевский Юрий Григорьевич
3. Я из СМЕРШа
Фантастика:
боевая фантастика
попаданцы
альтернативная история
7.06
рейтинг книги
Командир штрафбата

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

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

Проводник

Кораблев Родион
2. Другая сторона
Фантастика:
боевая фантастика
рпг
7.41
рейтинг книги
Проводник

Зайти и выйти

Суконкин Алексей
Проза:
военная проза
5.00
рейтинг книги
Зайти и выйти

Плеяда

Суконкин Алексей
Проза:
военная проза
русская классическая проза
5.00
рейтинг книги
Плеяда

Дело Чести

Щукин Иван
5. Жизни Архимага
Фантастика:
городское фэнтези
попаданцы
аниме
5.00
рейтинг книги
Дело Чести

Темный Лекарь 9

Токсик Саша
9. Темный Лекарь
Фантастика:
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Темный Лекарь 9

Идеальный мир для Социопата 3

Сапфир Олег
3. Социопат
Фантастика:
боевая фантастика
6.17
рейтинг книги
Идеальный мир для Социопата 3