javaSE@IT·互联网程序员

反射的应用

2017-04-13  本文已影响39人  风吹稻子

反射基础知识链接:http://www.jianshu.com/p/370073fad7e3

反射应用的场景

  1. 比如在编码阶段,我们不知道实例化的类名则:

     Class clazz = Class.forName("java.lang.String");
     clazz.newInstance();
    
  2. 比如我们在运行阶段,我们想访问Student这个类的私有属性name

     Student student = new Student();
     Class clazz = Student.class;
     Filed name = clazz.getDeclaredField("name");
     name.setAccessible(true);
     name.set("好人");
    

通过反射调用自身方法

    TestReflection c3 = new TestReflection();
    Method method = c1.getDeclaredMethod("info2", int.class);
    method.invoke(c3, 2);

方法:

public void info2(int a) {
    System.out.println(a);
    
}

测试结果:
2

利用反射修改私有属性

    package reflection;

import java.lang.reflect.Field;

public class TestStudent {

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
        Student student = new Student();
        //获取Student的对象
        Class s = student.getClass();
        //获取id属性并为其赋值
        Field id = s.getDeclaredField("id");
        //将私有属性设为可见
        id.setAccessible(true);
        id.setInt(student, 10);
        //获取姓名
        Field name = s.getDeclaredField("name");
        name.setAccessible(true);
        name.set(student, "光头强");
        //获取male并为其赋值
        Field male = s.getDeclaredField("male");
        male.setAccessible(true);
        male.setBoolean(student, true);
        
        System.out.println("id:"+student.getId());
        System.out.println("name:"+student.getName());
        System.out.println("id:"+student.isMale());     
    }

}

测试结果:

id:10
name:光头强
id:true

利用反射创建对象

 package reflection;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;

public class TestStudent {

    public static void main(String[] args) throws NoSuchFieldException, SecurityException, IllegalArgumentException,
            IllegalAccessException, NoSuchMethodException, InstantiationException, InvocationTargetException {

        Student student = new Student();
        Constructor c = student.getClass().getConstructor();
        // 第一种方法创建对象
        Student s = (Student) c.newInstance();
        // 第二种方法创建的对象
        Student s2 = student.getClass().newInstance();
        s.setId(10);
        s2.setId(20);
        System.out.println("id:" + s.getId());
        System.out.println("id:" + s2.getId());

    }

}

测试结果:

id:10
id:20

Class.newInstance()只能调用无参构造器,而且构造方法可见
Constructor.newInstance()可以调用有参构造器,在特定情况下调用不可见构造方法

利用反射创建可变数组

    package reflection;

import java.lang.reflect.Array;

public class TestStudent {
    
    public Object createArrayLength(Object array) {
        //获取数组对象,Class<?>为泛型
        Class<?> clazz = array.getClass();
        if(clazz.isArray()){
            //获取数组类型
            Class<?> componentType = clazz.getComponentType();
            //获取数组长度
            int length = Array.getLength(array);
            //创建新数组,并增加长度
            Object newArray = Array.newInstance(componentType, length+10);
            //将旧数组的数据复制给新数组
            System.arraycopy(array, 0, newArray, 0, length);
            return newArray;
        }
        return null;
    }
    
    public static void main(String[] args) {
        int[] array = new int[10];
        System.out.println("增加之前的数组长度:"+array.length);
        TestStudent ts = new TestStudent();
        int[] newArray = (int[]) ts.createArrayLength(array);
        System.out.println("增加之前的数组长度:"+newArray.length);

    }

}

测试结果:

增加之前的数组长度:10
增加之后的数组长度:20

注意:创建动态数组,可以使用ArrayUtils工具类,属于Commons Lang组件

链接知识点:泛型,Commons Lang组件

实例

题目:通过传入不同的字符串参数,使用反射来调用对应的方法

package reflection;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class Animal {

    public void run() {
        System.out.println("动物会跑");
    }

    public void eat() {
        System.out.println("动物会吃");
    }

    public static void main(String[] args) {
        String name = "/run";
        String name2 = "/eat";
        //运用反射获取对象
        Animal animal = new Animal();
        Class clazz = Animal.class;
        //获取方法名
        String methodName = animal.getName(name);
        String methodName2 = animal.getName(name2);
        try {
            //运用反射获取方法
            Method method = clazz.getDeclaredMethod(methodName, null);
            Method method2 = clazz.getDeclaredMethod(methodName2, null);
            //运用反射调用相应方法
            method.invoke(animal, null);
            method2.invoke(animal, null);
        } catch (Exception e) {
            // TODO: handle exception
        }

    }
    
    /**
     * 去掉字符的多余部分,获取方法名
     * @param name
     * @return
     */
    public String getName(String name) {
        // 去掉字符串的“/”,并取出前后空格,返回方法名
        String methodName = name.substring(1).trim();
        return methodName;
    }

}

测试结果:

动物会跑
动物会吃

反射与动态代理

创建一个销售接口

package reflection;
public interface Seller {
    void sell();
}

创建一个实现接口的类BookSeller

package reflection;

public class BookSeller implements Seller {
    public void sell() {
        System.out.println("销售人员在卖书");
    }
}

创建一个代理商的类

package reflection;

import java.lang.reflect.InvocationHandler;

public class Agency implements InvocationHandler{
    public Object invoke(Object arg0, java.lang.reflect.Method arg1, 
        Object[] arg2) throws Throwable {
        System.out.println("代理人员在卖书");
        return null;    
    }
}

测试类

package reflection;

import java.lang.reflect.Proxy;

public class Test {

    public static void main(String[] args) {
        Seller seller = new BookSeller();
        System.out.println("使用普通方法卖书");
        seller.sell();
        System.out.println("使用代理方法卖书");
        //获取类的加载器
        ClassLoader loader = Seller.class.getClassLoader();
        //指定代理的接口(Seller)和代理商(new Agency())
        seller = (Seller) Proxy.newProxyInstance(loader,new Class[]{Seller.class},new Agency());
        seller.sell();      
    }   
}

测试结果

使用普通方法卖书
销售人员在卖书
使用代理方法卖书
代理人员在卖房子

链接知识点:动态代理

上一篇 下一篇

猜你喜欢

热点阅读