Thinking in Java 笔记:Reflection

反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力.
Java反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类;在运行时构造任意一个类的对象;在运行时判断任意一个类所具有的成员变量和方法;在运行时调用任意一个对象的方法;生成动态代理。

在TIJ中,反射被作为一个子章节被放在RTTI(run time type information)中,书中的标题是Reflection:runtime class information,两者的区别就在于一个是type information一个是class information,RTTI相对与反射的局限就在与一个类的类型在编译期必须已知,编译器在编译器打开和检查.class文件,这样你就可以用"普通"的方式调用一个对象的所有方法,对于反射机制来说,.class文件在编译期是不可获取的,JVM在运行期获得一个未知类型对象,对它进行检查看它属于哪个特定的类,在这之后做任何其它事情之前,JVM必须加载这个类的class对象,因此,.class文件对JVM来说应该是可获取的(本地机器或网络取得)

关于动态代理:
动态代理机制的核心是InvocationHandler(调用处理器)这个接口。在动态代理中,是基于面向接口编程的。首先针对具体实例通过反射机制得到该类的类加载器、实现的接口,并对该类对象构造一个调用处理器类。并且实现invoke(Object proxy, Method method, Object[] args)方法,这个是核心处理方法。然后用构造实例的代理对象,这个代理对象的产生正是基于前面的实例的classloader、interfaces[](可能实现多个接口)及InvocationHandler实例。这样对代理对象调用实例的方法,就会将请求转发到调用处理器,在method.invoke(proxied, args);的前后的代码就是代理所需要实现的功能.

动态代理的内部实现——代码生成:
在Sun的Proxy实现中调用了 sun.misc.ProxyGenerator 类的 generateProxyClass( proxyName, interfaces) 方法,其返回值为 byte[] 和 class 文件的内存类型一致,即生成了一个代理类.
一个比较典型的动态代理程序:
package com.juice.rtti.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

interface TestInterface {
void doSth();
}
class RealSub implements TestInterface{

@Override
public void doSth() {
System.out.println("dosth");

}
}
class Handler implements InvocationHandler{
private TestInterface real;
public Handler(TestInterface real) {
this.real = real;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("hello");
return method.invoke(real, args);
}

}
public class ProxyTest {
public static void main(String[] args) {
TestInterface real = new RealSub();
TestInterface proxy = (TestInterface)Proxy.newProxyInstance
(TestInterface.class.getClassLoader(), new Class<?> [] {TestInterface.class}, new Handler(real));
proxy.doSth();
}
}

使用Reflect会破坏封装?
从某种程度上说,确实是这样的,对于一个Class文件,你可以使用javap -private Classname命令获得所有的成员变量和方法(包括声明为private的),这样任何人都可以使用Method的invoke方法和Filed的set方法来调用private方法或设置private的成员变量.
调用某对象的某方法:
static void callHiddenMethod(Object a, String methodName)
throws Exception {
Method g = a.getClass().getDeclaredMethod(methodName);
g.setAccessible(true);
g.invoke(a);
}

设置成员变量值:
    WithPrivateFinalField pf = new WithPrivateFinalField();
System.out.println(pf);
Field f = pf.getClass().getDeclaredField("i");
f.setAccessible(true);
System.out.println("f.getInt(pf): " + f.getInt(pf));
f.setInt(pf, 47);

值得注意的是:如果成员变量被声明为final,那么Field的set()方法不会改变该变量的值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值