反射在Java中的应用

在我们平时的项目开发中,虽然很少用到反射机制,但实际上很多设计、开发都与反射机制有关,例如利用反射实现工厂设计模式,利用反射实现动态代理,利用反射获取注解信息等等,下面就基于这三种应用进行相关的描述

一、利用反射实现工厂设计模式

interface IMessage {
    public void send();
}
class NetMessage implements IMessage {

    @Override
    public void send() {
        System.out.println("我是netMessage");
    }
}
class ServiceMessage implements IMessage {

    @Override
    public void send() {
        System.out.println("我是serviceMessage");
    }
}
class Factory {
    private Factory(){}
    public static IMessage getInstance(String className){
        try{
            return (IMessage) Class.forName(className).getDeclaredConstructor().newInstance(); 
        }catch(Exception e){
            e.printStackTrace();
        }
        
    }
}
public class Test {
    public static void main(String[] args) {
        IMessage iMessage = Factory.getInstance("NetMessage");
        iMessage.send();
    }
}

这样我们就可以在主类中只传入一个带有包名+类名的字符串就可以从工厂类中获取到对象的实例,避免了在工厂类中重复的类型判断语句

二、利用反射实现动态代理

jdk的动态代理主要和Proxy类和InvocationHandler接口相关
InvocationHandler是代理实例调用处理程序实现的接口
Proxy类提供用于创建动态代理和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类

interface IMessage{
    public void send();
}
class RealHandler implements IMessage{

    @Override
    public void send() {
        System.out.println("真实业务类输出");
    }
}
class ProxyHandler implements InvocationHandler{
    private Object target;

    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
//        利用反射机制返回一个Proxy代理类
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        log(method.getName());   //实现日志打印功能,代理类相对于真实业务类多出来的方法
        method.invoke(target,args);  //调用真实业务类的send方法
        return null;
    }
    public void log(String str){
        System.out.println(str);
    }
}
public class Solution {
    public static void main(String[] args){
        IMessage iMessage = new RealHandler();
        ProxyHandler proxyHandler = new ProxyHandler();
        IMessage proxy = (IMessage) proxyHandler.bind(iMessage);
        proxy.send();
    }
}

三、自定义注解和利用反射获取注解信息

一个基本的注解主要由以下三部分组成
反射在Java中的应用_第1张图片
(1)@Target 是用来限定注解是用在哪些Java元素上面的,ElementType枚举类型定义如下:

public enum ElementType {
    /** 类,接口(包括注解类型)或枚举的声明 */
    TYPE,

    /** 属性的声明 */
    FIELD,

    /** 方法的声明 */
    METHOD,

    /** 方法形式参数声明 */
    PARAMETER,

    /** 构造方法的声明 */
    CONSTRUCTOR,

    /** 局部变量声明 */
    LOCAL_VARIABLE,

    /** 注解类型声明 */
    ANNOTATION_TYPE,

    /** 包的声明 */
    PACKAGE
}

(2)@Retention用来修饰自定义注解的生命周期
注解的生命周期有三个阶段:1、Java源文件阶段;2、编译到class文件阶段;3、运行期阶段,分别对应了枚举类RetentionPolicy的SOURCR、CLASS、RUNTIME
(3)用@interface来自定义一个注解
自定义注解并利用反射获取注解信息

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation{
    public String name();
    public int age() default 12;
}
class Message{
    @MyAnnotation(name="zhangsan")
    public void send(String msg){
        System.out.println(msg);
    }
}
public class Solution {
    public static void main(String[] args){
        try{
            Method method = Message.class.getMethod("send",String.class);
            MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
            String msg = myAnnotation.name() + "----" + myAnnotation.age();
            method.invoke(Message.class.getDeclaredConstructor().newInstance(),msg);
        } catch(Exception e){
            e.printStackTrace();
        }
    }
}

在这里插入图片描述

你可能感兴趣的:(java后端)