Эккель Брюс
Шрифт:
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");
}
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");