现在的位置: 首页 > 综合 > 正文

黑马程序员—反射2

2013年02月13日 ⁄ 综合 ⁄ 共 6198字 ⁄ 字号 评论关闭

---------------------- android培训java培训、期待与您交流! ----------------------

3、访问类中的字段
可以通过Class中的getFields()、getField(String name)以及getDeclaredFields()、getDeclaredField(String name)来访问类的字段。方法名中带Declared与不带Declared的含义同构造方法。假如现在想改变private类型的needCheck的值,可以用getDeclaredField(String name)方法先获取字段对象,再修改其值:

package com.ticmy.reflect;
import java.lang.reflect.Field;
public class Test {
    public static void main(String[] args) throws Exception
{
        Class<?> clazz = Class.forName("com.ticmy.reflect.ArticleManage");
        ArticleInterface inst = (ArticleInterface)clazz.newInstance();
        Field field = clazz.getDeclaredField("needCheck");
        field.setAccessible(true);
        field.setBoolean(inst, false);
        inst.add("this is a short article");
    }
}

获取到Field对象后,通过调用其setBoolean方法修改其值。其第一个参数为想要改变字段值的对象,若是static字段,该参数可为null;如果字段为其它类型,可以调用Field类的其它setXXX方法来修改。注意到代码中有一句field.setAccessible(true),如果没有这句会报以下错误,不允许修改private变量的值,将其设置为true,就允许改变了:
Exception in thread “main” java.lang.IllegalAccessException: Class com.ticmy.reflect.Test can not access a member of class com.ticmy.reflect.ArticleManage with modifiers “private”

4、访问类中的方法
Class类中提供了getMethods()、getMethod(String name, Class… parameterTypes)以及getDeclaredMethods()、getDeclaredMethod(String name, Class… parameterTypes),其情况类似于构造方法,毋庸多言。需要说的是其带参数的方法,第一个参数是方法名,后面是对应方法的参数类型。假如这里要调用modify方法,可以先通过getMethod(String name, Class… parameterTypes)获得对应的Method对象,然后通过invoke调用:

package com.ticmy.reflect;
import java.lang.reflect.Method;
public class Test {
    public static void main(String[] args) throws Exception
{
        Class<?> clazz = Class.forName("com.ticmy.reflect.ArticleManage");
        ArticleInterface inst = (ArticleInterface)clazz.newInstance();
        Method method = clazz.getMethod("modify"long.class,
String.
class);
        method.invoke(inst, 3"this is a short article");
    }
}

invoke的第一个参数表示调用的是哪个对象的modify方法,后面是ArticleInterface接口中modify方法按声明顺序排列的实际参数。

5、上述内容是关于反射中常用的一些方法和用法,更多功能参见java.lang.Class,java.lang.reflect.Method、java.lang.reflect.Field、java.lang.reflect.Constructor等类的JAVA API说明。

6、反射和动态代理的结合。
动态代理用于创建动态代理类,这些类不需要以java class文件的形式存在。动态代理相关的类为:java.lang.reflect.Proxy。可以通过其newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)方法创建一个代理类,其中,loader为定义代理类的类加载器,interfaces为生成的代理类要实现的接口列表,h为指派方法调用的调用处理程序。在ArticleManage示例类中,add和modify方法中都有if((!needCheck)
|| checkContent())的判断,或许还有更多方法需要这种判断,在每个方法里都写这样的判断实在是太麻烦,动态代理+方法反射调用就可以帮我们解脱痛苦:
现在将ArticleManage实现中的if判断删除:

package com.ticmy.reflect;
  
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
  
public class ArticleManage implements ArticleInterface {
    private final Map<Long, String> articles;
    private boolean needCheck;
    private final AtomicLong idIncr = new AtomicLong(1);
    public ArticleManage(boolean needCheck) {
        System.out.println("带参数的构造方法");
        this.needCheck = needCheck;
        articles = new ConcurrentHashMap<Long, String>();
    }
  
    public ArticleManage() {
        System.out.println("默认构造方法");
        this.needCheck = true;
        articles = new ConcurrentHashMap<Long, String>();
    }
  
    public void del(long id) throws Exception
{
        System.out.println("删除文章");
        articles.remove(id);
    }
  
    public void add(String content) throws Exception
{
        System.out.println("添加文章");
        articles.put(idIncr.getAndIncrement(), content);
    }
  
    public void modify(long id,
String content) 
throws Exception {
        System.out.println("修改文章内容");
        articles.put(id, content);
    }
  
    public boolean checkContent() throws Exception
{
        System.out.println("检查文章内容");
        Random random = new Random();
        int value = random.nextInt(100);
        if(value < 20) {
            //20%概率失败
            throw new Exception("文章内容不合法");
        }
        return true;
    }
  
    public boolean isNeedCheck() {
        return needCheck;
    }
}

通过动态代理为其加上判断功能

package com.ticmy.reflect;
  
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
  
public class Test {
    public static void main(String[] args) throws Exception
{
        ArticleManage delegationObj = new ArticleManage();
  
        ArticleInterface inst = (ArticleInterface)Proxy.newProxyInstance(
                ArticleInterface.class.getClassLoader(),
                new Class[]{ArticleInterface.class},
                new ArticleManageInvocationHandler(delegationObj));
        inst.add("this is a short article");
  
    }
  
    static class ArticleManageInvocationHandler implements InvocationHandler
{
        private ArticleManage delegationObj;
        public ArticleManageInvocationHandler(ArticleManage delegationObj) {
            this.delegationObj = delegationObj;
        }
        public Object invoke(Object proxy, Method method, Object[] args) throws Exception
{
            String methodName = method.getName();
            Object ret = null;
            long start = System.currentTimeMillis();
  
            if(methodName.equals("add")) {
                ret = method.invoke(delegationObj, args);
            else {
                if((!delegationObj.isNeedCheck()) || delegationObj.checkContent()) {
                    ret = method.invoke(delegationObj, args);
                }
            }
            long end = System.currentTimeMillis();
            System.out.println("[方法调用][" + methodName + "]耗时:" +
(end - start) + 
"ms");
            return ret;
        }
    }
}

看这部分

ArticleInterface inst = (ArticleInterface)Proxy.newProxyInstance(
        ArticleInterface.class.getClassLoader(),
        new Class[]{ArticleInterface.class},
        new ArticleManageInvocationHandler(delegationObj));

让生成的代理类实现ArticleInterface接口,这样就可以将newProxyInstance的对象强制转换成ArticleInterface类型了。

在InvocationHandler中,可以看到其invoke方法参数中有个Method,这个Method对象是代理接口中的那些方法,例如这里将其强制转换成ArticleInterface后,假设调用了add方法,InvocationHandler中invoke方法的method就相当于ArticleInterface.class.getMethod(“add”, String.class)。

在这个例子中,当调用inst的方法时,就会自动去调用ArticleManageInvocationHandler中的invoke方法。invoke方法的第三个参数,就是调用inst中方法时传的参数。invoke方法的第一个参数即为生成的代理类对象本身,很多时候这个参数用处不大。
既然调用inst的方法时会调用这个invoke方法,那就可以在里面做一些事情了。像上面在调用实际方法之前给其加了判断,为整个方法调用计时等等,有没有种面向切面的感觉?

这是很常用的一种编程模式,如在现实中很多操作需要验证用户是否已经登录,那么就可以通过这种方式来做。

如果用了spring,可以使用spring的AOP来做,道理是类似的。

---------------------- android培训java培训、期待与您交流! ----------------------

详细请查看:http://edu.csdn.net/heima

抱歉!评论已关闭.