反射就是把java类中的各种成为映射成一个个的java对象; java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
Class cls1 = Person.class;
``Class cls2 = new Person().getClass();
Class cls3 = Class.forName("com.wenlong.Person");
第三种方法除了能得到类模板对象还能加载此类。
new Instance():创建此Class对象所表示的类的一个新实例。
getFlied(String name):返回一个Field对象,它反映此Class对象所表示的类或接口的指定公共字段;
getFlieds():返回一个Field对象,它反映此Class对象所表示的类或接口的所有公共字段;
getDeclaredField(String name):返回一个Field对象,它反映此Class对象所表示的类或接口的指定已声明字段;
getDeclaredFields:返回一个Field对象,它反映此Class对象所表示的类或接口的指定所有字段;
getMethod(String name,,Class... parameterTypes):返回一个Method对象,它反映此Class对象所表示的类或接口的指定公共成员方法。
此外还有getMethods(),getDeclaredMethod(String name,Class... parameterTypes),getDeclaredMethods()方法 用法与Flied相似。
getConstructor(Class... parameterTypes):返回一个Constructor对象,它反映此Class对象所表示类的指定公共构造方法,当然还有getConstructors()等其他三个方法。
invoke(Object obj,Object... args):对带有指定参数的指定对象调用由此Method对象表示的底层方法。
Class cls = Person.class;
//此时m1指向的是Person类的方法名是showName,参数列表是String的这个方法
Method method = cls.getMethod("showName",String.class);
//创建cls对象所表示类的一个实例
Object obj = cls.newInstance();
//调用obj中得到的method指定的方法showName带String参数的方法
method.invoke(obj,"zs");
如果要调用类中带参的构造器来创建对象,就要用Constructor对象来描述带参的构造器,再通过该对象的newInstance方法得到一个类的对象。
Class cls = new Person().getClass();
//获取所有公共构造方法
Constructor[] constructor = cls.getConstructors();
//获取指定公共构造方法
Constructor constructor = cls.getConstructor(String.class);
//指定有参构造器创建对象
Object obj = constructor.newInstance("abc");
创建student类:
public class Student {
public void show(){
System.out.println("is show()");
}
}
配置文件(pro.txt):
className = cn.reflect.Student
methodName = show
测试类:
package com.reflect.configFile;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
/*
* 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改
* 我们只需要将新类发送给客户端,并修改配置文件即可
*/
public class TestConfigFile {
public static void main(String[] args) throws Exception {
//通过反射获取Class对象
Class stuClass = Class.forName(getValue("className"));//"cn.fanshe.Student"
//2获取show()方法
Method m = stuClass.getMethod(getValue("methodName"));//show
//3.调用show()方法
m.invoke(stuClass.newInstance());
}
//此方法接收一个key,在配置文件中获取相应的value
public static String getValue(String key) throws IOException{
Properties pro = new Properties();//获取配置文件的对象
FileReader in = new FileReader("pro.propertities");//获取输入流
pro.load(in);//将流加载到配置文件对象中
in.close();
return pro.getProperty(key);//返回根据key获取的value值
}
}
当我们升级这个系统时,不要Student类,而需要新写一个Student2的类时,这时只需要更改pro.txt的文件内容就可以了。代码就一点不用改动 要替换的student2类:
public class Student2 {
public void show2(){
System.out.println("is show2()");
}
}
配置文件更改为:
className = cn.reflect.Student2
methodName = show2
代码示例:
public class CrossGenericity{
/*通过反射越过泛型检查
*例题:像一个String泛型的集合添加一个Integer类型的值;
*/
public static void main(String[] args) throws Exception{
ArrayList<String> strList = new ArrayList<>();
strList.add("aaa");
strList.add("bbb");
//得到strList的字节码对象
Class cls = strList.getClass();
//获取add方法
Method method = cls.getMethod("add",Object.class);
//调用add方法
method.invoke(cls,10);
//遍历集合
for(Object obj : strList){
System.out.println(obj);
}
}
理解反射的机制是理解动态代理原理的基础,希望今天整理的内容对大家有所帮助