1.前言

    反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性,这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

2.基础使用

测试类如下:

//User.java
public class User extends BaseUser implements Serializable {
    protected static final long serialVersionUID = 1L;
    private int userId;
    public String userName;
    public boolean isMale;

    public User(int userId, String userName, boolean isMale) {
        this.userId = userId;
        this.userName = userName;
        this.isMale = isMale;
    }

    @Override
    public String toString() {
        return "userId=" + userId + ",userName=" + userName + ", isMale=" + isMale;
    }

    private void print(String userName) {
        System.out.println(toString());
    }
}
  • 1.获取类的Class对象
public static Class<?> forName(String className) 
  • 2.获取所有的构造函数:getConstructors()
//获取当前类的public修饰的构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)
public Constructor<?>[] getConstructors()

public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
//Returns an array of {@code Constructor} objects reflecting all the constructors declared by the class represented by this
//{@code Class} object.These are public, protected, default (package) access, and private constructors.
////获取当前类的所有构造方法
public Constructor<?>[] getDeclaredConstructors()
  • 3.创建实例:newInstance()
//相当于调用无参的默认构造器new一个对象
public T newInstance()
  • 4.获取所有的属性:getDeclaredFields();
//获取当前类的public成员变量,包含父类或接口中的成员变量
public Field getField(String name)
public Field[] getFields()
//获取当前类所有的成员变量,没有父类或接口中的成员变量
public Field getDeclaredField(String name)
public Field[] getDeclaredFields()
  • 5.获取类的方法:getMethods()
//获取当前类的方法信息,当前类自己和继承父类或接口的public方法
public Method getMethod(String name, Class<?>... parameterTypes)
public Method[] getMethods()
//获取当前类的所有方法,不包括父类的
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
public Method[] getDeclaredMethods()
  • 6.获取所有实现的接口:getInterfaces()
public Class<?>[] getInterfaces()
  • 7.获取父类:getSuperclass()
public native Class<? super T> getSuperclass()

3.实例

  • 反射调用私有方法:
private static void callPrivateMethod() {
        try {
        	//先获取类的Class实例
            Class<?> aClass = Class.forName("main.serializabletest.User");
            //根据方法名和参数列表获取对应的Method实例
            Method print = aClass.getDeclaredMethod("print", String.class);
            //通过构造方法获取类实例
            Constructor<?> declaredConstructor = aClass.getDeclaredConstructor(int.class, String.class, boolean.class);
            Object userObj = declaredConstructor.newInstance(18, "123", true);
            //invoke()传入对象实例和参数调用私有方法
            if (print != null) {
                print.setAccessible(true);
                print.invoke(userObj, "print test");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这种适用于,某些系统API是公开的,但是因为要实现一些功能必须要调用,可以采用上面的方式调用。注意调用private方法时,一定要先调用setAccessible(true),否则会报IllegalAccessException异常,无法正常调用。

  • 另外反射常用在动态代理中,举例如下:
/**
 * Sell接口,代理类和被代理类都应该实现这个方法
 *
 * @author Mr.torto
 */
public interface Sell {
    void sell();

    void ad();
} 
/**
 * 生产厂家,被代理类
 *
 * @author Mr.torto
 */
public class Vendor implements Sell {
    public void sell() {
        System.out.println("Has been called sell() method");
    }

    public void ad() {
        System.out.println("Has been ad() method");
    }
}

/**
 * @author Mr.torto
 * 测试动态代理
 */
public class Main {
    public static void main(String[] args) {
        Sell realObj = new Vendor(); //被代理者,主题类
        Sell proxyObj = (Sell) Proxy.newProxyInstance(realObj.getClass().getClassLoader(),
                new Class[]{Sell.class}, new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("Call realSubject before");
                        //调用被代理者真正的业务实现方法,这里具体就会转调到Vendor::sell(),Vendor::ad()方法
                        Object result = method.invoke(realObj, args);
                        System.out.println("Call realSubject after");
                        return result;
                    }
                });
        //转调到InvocationHandler的invoke方法中
        proxyObj.sell();
        proxyObj.ad();
    }
}

输出:

Call realSubject before
Has been called sell() method
Call realSubject after
Call realSubject before
Has been ad() method
Call realSubject after

相对于动态,以为不管是静态代理还是动态代理 ,理论上是一定要调用被代理者实现真实业务逻辑的,所以代理本质上是在被代理类的基础上加些业务,或者说更偏业务逻辑的东西。在代码上就表现为在调用被代理者的前后,加一些预处理,或是加些后续处理。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐