反射基础知识链接:http://www.jianshu.com/p/370073fad7e3
反射应用的场景
-
比如在编码阶段,我们不知道实例化的类名则:
Class clazz = Class.forName("java.lang.String"); clazz.newInstance();
-
比如我们在运行阶段,我们想访问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();
}
}
测试结果
使用普通方法卖书
销售人员在卖书
使用代理方法卖书
代理人员在卖房子
链接知识点:动态代理