java反射

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()方法来产生对象时,无需使用强制类转换,系统会执行严格的检查
     */
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值