1、反射的概念
反射是java语言的一个特性,它允程序在运行时(注意不是编译时期)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。一个常见的例子是在JavaBean中,一些组件可以通过一个构造器来操作。这个构造器就是用的反射在动态加载的时候来获取的java中类的属性的。
2、反射相关的核心类
public classUser {privateString name;private intage;publicUser(){super();
}public User(String name, intage) {super();this.name =name;this.age =age;
}publicString sayHello(String name){return "Hello,"+name;
}//get set...
}
2.1、Class
java中获取对象字节码的方式
@Testpublic void classTest() throwsException{
User user= newUser();
String className= "org.javacode.model.User";
Class> clazz1 =Class.forName(className);
Class> clazz2 = User.class;
Class> clazz3 =user.getClass();
System.out.println(clazz1==clazz2);
System.out.println(clazz2==clazz3);
}
输出结果都为true,可见同一个类中只有唯一一份字节码。获取Class对象有3种方式。
2.2、Constructor 构造器
@Testpublic void constructor() throwsException{//通过constructor构造对象
Class clazz = User.class;
Constructor constructor = clazz.getConstructor(String.class,int.class);
User user= constructor.newInstance("zhangsan",26);
String name=user.getName();
System.out.println(name);
}
通过Constructor构造对象,除此之外还有的方法:
getConstructors()获取所有的构造器;
getDeclaredConstructor(Class>... parameterTypes) 获取声明给定参数的构造器
getDeclaredConstructors() 获取所有声明的构造器
newInstance(Object... initargs) 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
...
2.3、Method 方法
@Testpublic void method() throwsException{
Class clazz = User.class;
Method method= clazz.getDeclaredMethod("sayHello", String.class);
Object obj=clazz.newInstance();
Object resultObj= method.invoke(obj, "Hehe");
System.out.println(resultObj.toString());
}
通过class获取Method,其中比较核心的方法是method.invoke(Object , parameters...); 也就是通过Method调用对象的某一个方法,参数是动态的,这主要是为了区别方法的重载(Overloading) 。
2.4、Field 属性
@Testpublic void field() throwsException{
Class clazz = User.class;
Field[] fields=clazz.getDeclaredFields() ;for(Field field : fields) {
System.out.println(field.getName());
}
}
通过getDeclaredFields() 可以获取对象中所有的属性。在Constructor,Method,Field中都有getXXX和getDeclaredXXX的方法,他们的区别主要是访问权限的问题,getXXX 是不能获取private的属性,构造器以及方法的。
3、反射和工厂模式的结合
public interfaceBaseCache {public voidput(String key,Object value);
}public class LocalCache implementsBaseCache{public voidput(String key, Object value) {
System.out.println("local...");
}
}public class RedisCache implementsBaseCache {public voidput(String key, Object value) {
System.out.println("redis...");
}
}
public classCacheFactory {public staticBaseCache getInstance(String className) {try{
Class> clazz =Class.forName(className);
BaseCache cache=(BaseCache) clazz.newInstance();returncache;
}catch (ClassNotFoundException |InstantiationException|IllegalAccessException e) {
e.printStackTrace();return null;
}
}
}
通过指定类名我们可以通过反射到具体的实现类,最起码在这里是可以减少好几个if else 的,那么的更好一点做法可以将className写到配置文件中,当需要不同的实现类时,只要改配置文件即可,而不用修改代码。