Java反射
1.通过反射查看类的信息
1.1 获取Class对象
每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过Class对象就可以访问到JVM中的这个类,在java程序中获得Class对象通常有如下三种方式。
- 使用Class类的forName(String clazzName)静态方法, clazzName为某个类的全限定类名.
- 调用某个类的class属性获取该类对应的class对象,例如User.class
- 调用某个对象的getClass()方法
但如果程序只能获得一个字符串,则只能使用第一种方式,使用Class的forName(String clazzName)方法获取class对象时,该方法可能抛出一个ClassNotFoundException异常。
1.2 从Class中获取信息
获取Class中的信息提供了很多API方法,查阅API文档。列出几个常用的方法。
获取构造方法
Constructor<T>getConstructor(Class<?>..parameterTypes) Constructor<T> getConstructors();返回此Class对象的所有public构造器
获取Class对应类包含的方法
Method getMethod(String name,Class<?>...parameterTypes)返回指定的方法.
Method getMethods();返回此Class对象表示类的所有 public方法
- 获取Class对应类的成员变量
Field getField(String name);返回指定名称的public成员变量
Field getFields();返回此类所有public类型的成员变量
- 访问Class对应类上包含的Annotation
<T extends Annotation> T getAnnotation(Class<T> annotationClass);获取指定类型的Annotation,如果该类型的注解不存在,则返回null.
Annotation[] getAnnotations();返回修饰该Class对象对应类上存
在的所有Annotation.
- 获取接口,包名,全路径名
Package getPackage()
String getInterfaces();
Package getPackage();
String getSimpleName();
boolean isAnnotation();
2.使用反射生成并操作对象
2.1 创建对象
通过反射来生成对象有如下两种方式。
- 使用Class对象的newInstance()方法来创建该Class对象对应类的实例,这种方式要求该Class对象的对应类有默认构造器,而执行newInstance()方法实际上是利用默认构造器来创建该类的实例。
- 先使用Class对象获取指定的Constructor对象,然后在调用Constructor对象的newInstance()方法来创建Class对象对应类的实例。通过这种方式可以选择使用指定的构造器来创建实例。
2.2 调用方法
当获取得到某一个类对应的Class对象后,就可以通过该Class对象的getMethods()方法或者getMethod()方法来获取全部方法或指定方法。
Object invoke(Object obj,Object...args);obj是执行该方法的主调,后面的args是执行该方法时传入该方法的实参.
3.访问成员变量值
通过Class对象的getFields()或getField()方法可以获取该类所包括的全部成员变量或指定成员变量Field提供了设置与读取成员变量的值.
- getXxx(Object obj); 获取obj对象的改成员变量的值,此处的Xxx对应8中基本类型,如果该成员变量的类型是引用类型,则取消get后面的Xxx.
- setXxx(Object obj,Xxx val);将object对象的该成员变量设置成val值。
4. 使用反射生成JDK动态代理
Proxy提供了用于创建动态代理和代理对象的静态方法,它也是所有动态代理类的父类。
static Object newProxyInstance(ClassLoader loader,Class<?>...interfaces);创建一个动态代理类所对应的Class对象,classLoader参数指定生成动态代理类的类加载器,interfaces是该代理类将实现interfaces所指定的多个接口。
static Class<?> getProxyClass(ClassLoader loader,Class<?>...interfaces)创建一个动态代理类所对应的Class对象。
创建动态代理类:定义个类实现InvocationHandler,需要重写invoke()方法------调用代理对象的所有方法时都会被替换成调用该invoke()方法,该invoke()方法中三个参数
proxy: 代表动态代理对象
method:代表正在执行的方法
args: 代表调用目标方法时传入的实参
/**
*用户操作接口
*/
public interface UserDao {
void addUser();
void deleteUser();
}
/**
*用户操作实现类
*/
public class UserDaoImpl implements UserDao{
/**
* 添加用户
*/
@Override
public void addUser(){
System.out.println("添加用户操作");
}
/**
* 删除用户
*/
@Override
public void deleteUser(){
System.out.println("删除用户操作");
}
}
/**
* 动态代理操作类
*/
public class UserDaoProxy implements InvocationHandler{
private UserDao userDao;
public UserDaoProxy(UserDao userDao){
super();
this.userDao = userDao;
}
public UserDao createProxy(){
//第一种方式创建代理对象
UserDao proxy = (UserDao) Proxy.newProxyInstance(userDao.getClass().getClassLoader(),userDao.getClass().getInterfaces(),this);
return proxy;
/*//第二种方式创建代理对象
Class proxyClass = Proxy.getProxyClass(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces());
Constructor ctor = proxyClass.getConstructor(new Class[]{InvocationHandler.class});
UserDao proxy = (UserDao) ctor.newInstance(this); */
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
if(name.equals("addUser")){
//记录该方法的日志
System.out.println("添加用户日志记录");
Object invoke = method.invoke(userDao, args);
return invoke;
}else if(name.equals("deleteUser")){
//记录该方法的日志
System.out.println("删除用户日志记录");
Object invoke = method.invoke(userDao, args);
return invoke;
}else{
return method.invoke(userDao,args);
}
}
}
//测试
public class Test {
public static void main(String[] args){
UserDao userDao = new UserDaoImpl();
UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
UserDao proxy = userDaoProxy.createProxy();
proxy.addUser();
proxy.deleteUser();
}
}
5. 反射和泛型
使用Class泛型可以避免强制类型转换,例如,下面提供一个简单的对象工厂,该对象工厂可以根据指定类来提供该类的实例。
public class ObjectFactory {
public static Object getInstance(String clsName){
try{
Class cls = Class.forName(clsName);
return cls;
}catch (Exception e){
e.printStackTrace();
return null;
}
}
// Date d = (Date)ObjectFactory.getInstance("java.util.Date");
// 获取实例后需要强制类型转换
// Date d = (Date)ObjectFactory.getInstance("java.util.Date");
// 出现ClassCastException
public static<T> T getInstance(Class<T> cls){
try {
return cls.newInstance();
}catch (Exception e){
e.printStackTrace();
return null;
}
}
/**
* Date d = ObjectFactory.getInstance(Date.class);
* getInstance()方法来产生对象时,无需使用强制类转换,系统会执行严格的检查
*/
}