接口与类型信息
interface关键字的一种重要目标就是允许程序员隔离构件,进而降低耦合性。为了避免客户端程序员将接口类对象向下转型,可以对实现使用包访问权限。对Method对象或者域对象调用setAccessible(true)方法,可以获取各种甚至private权限的对象。例子如下:
包访问权限的类C:
public interface A {
void f();
}
class C implements A {
public void f() {
System.out.println("public C.f()");
}
public void g() {
System.out.println("public C.g()");
}
void u() {
System.out.println("package C.u()");
}
protected void v() {
System.out.println("protected C.v()");
}
private void w() {
System.out.println("private C.w()");
}
}
获取类C的方法:
public class HiddenC {
public static A makeA() {
return new C();
}
}
class HiddenImplementation {
public static void main(String[] args) throws Exception {
A a = HiddenC.makeA();
a.f();
System.out.println(a.getClass().getName());
callHiddenMethod(a, "g");
callHiddenMethod(a, "u");
callHiddenMethod(a, "v");
callHiddenMethod(a, "w");
}
static void callHiddenMethod(Object a, String methodName) throws Exception {
Method g = a.getClass().getDeclaredMethod(methodName);
g.setAccessible(true);
g.invoke(a);
}
}
/* Output:
public C.f()
typeinfo.packageaccess.C
public C.g()
package C.u()
protected C.v()
private C.w()
从该例子可看出,通过使用反射,仍旧可以到达并调用所有方法,甚至是private方法。如果知道方法名,你就可以在其Method对象上调用setAccessible(true),就像在callHiddenMethod()中看到的那样。也从中可以看出,对反射没有隐藏任何东西。而对final成员的修改是安全的,但是其实运行时系统会在不抛出异常的情况下不接受任何修改,所以实际上还是没改成。