java反射

来源:互联网 发布:淘宝团队建设 编辑:程序博客网 时间:2024/05/16 18:18

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()方法来产生对象时,无需使用强制类转换,系统会执行严格的检查     */}
原创粉丝点击