关于Java反射的总结

Java的反射应用场景很多,但是每次都感觉有些懵,故作此文作为总结。

反射是什么

首先,反射,那肯定有正的吧。

正向

Man man=new Man();
man.sayHello();

反射

Class clazz = Man.class.getClass(); //获取Class类
Man man = (Man) clazz.newInstance(); // 用Class类创建实例
man.sayHello(); //调用实例方法

这边难免会联想到Spring的IOC了,其实Spring的IOC设计思想也是用到了反射的机制,使用反射在BeanFactory中生成对象。

反射什么用

当我们很明确需要将Man类实例化,自然可以用new的方式来创建对象实例。但是在某些场景并不明确new的对象是什么的时候,我们或许可以用多态的方式进行处理。

class abstract Human{}
class Man extends Human{}
class Woman extends Human{}

Human human1=new Man();
Human human2=new Woman();

用反射的方式也可以处理

Class clazz = Man.class.getClass(); //获取Class类
Man man = (Man) clazz.newInstance(); // 用Class类创建实例

但是仅仅用来创建对象,那反射也太没用了。学过JVM的都知道Class对象为class文件经过加载、链接和初始化的过程作为一个对象而存在,里面含有类的元信息。

  1. 获得构造方法

            Class clazz = Man.class.getClass();
            Constructor constructor = clazz.getConstructor();
            constructor.newInstance(); // 通过构造器创建实例也是一种利用反射机制创建实例的手段
    
  2. 获得某个方法并且使用该方法

            Class clazz = Man.class.getClass();
            Man man = (Man) clazz.newInstance();
            Method sayHelloMethod = clazz.getMethod("sayHello", int.class); //获取方法信息,通过指定的方法名和返回类型
            sayHelloMethod.invoke(man,...方法参数);
    
  3. 获取字段

            Field field=clazz.getField("name");
    

看到了现在终于明白了吧?其实类的反射机制就是通过Class为入口,使用Class来灵活的创建、使用对象。可以通过传递类的全路径、方法名作为调用某些方法的动态控制。

获取Class的方式

Class clazz=String.class

Class clazz=Class.forName("java.lang.String");

Class class=String.getClass();

应用场景

Spring的IOC机制

class UserFactory{
	public static UserDao getDao(){
		String classValue=...//来自于xml文件的解析
		Class clazz=Class.forName(classValue);//通过反射创建对象
		return (UserDao)class.newInstance();
	}
}

JDK动态代理

接口

public interface ManIntereface {
    public void sayHello();
}

目标类

public class Man implements ManIntereface{
    public void sayHello(){
        System.out.println("hello world");
    }
}

代理

public class HelloProxy implements InvocationHandler {
    private Object subject;

    public HelloProxy(Object object) {
        this.subject = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("方法调用前置处理");
        method.invoke(subject, args);
        System.out.println("方法调用后置处理");
        return null;
    }
}

调用测试

public class Client {
    public static void main(String[] args) {
        Man man = new Man();
        InvocationHandler handler = new ManProxy(man);
        ManIntereface manIntereface = (ManIntereface) Proxy
                .newProxyInstance(handler.getClass().getClassLoader(),
                        man.getClass().getInterfaces(),
                        handler);
        manIntereface.sayHello();
    }
}
posted @ 2021-10-24 03:42  月落随山隐  阅读(28)  评论(0)    收藏  举报