Java通過註解實現一個接口--利用反射與代理

概述

傳統實現接口的方式需要implement才行,通過註解實現一個接口可以減輕每次都要implement的繁瑣。本文實現一個Demo來展示如何通過註解實現一個接口。

Code

import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 利用反射與代理實現一個利用註解實現接口的功能,作爲展示,只支持函數接口,即接口中只有一個函數,且只支持一個接口。
 */
class Scratch {
    public static void main(String[] args) throws Exception {
        Lego lego = new Lego();
        Playable playable = buildInterfaceClass(lego, Playable.class, Play.class);
        playable.play();
    }

    /**
     *
     * @param object 有相應註解標記相應函數的類的對象
     * @param interfaceClazz 待實現接口的Class
     * @param annotationClazz 註解的Class
     * @param <T> 接口類型
     * @return 實現了接口的代理類對象
     */
    @SuppressWarnings("unchecked")
    public static <T> T buildInterfaceClass(Object object, Class<T> interfaceClazz, Class annotationClazz) {
        return (T) Proxy.newProxyInstance(interfaceClazz.getClassLoader(), new Class[]{interfaceClazz}, new InterfaceHandler(object, annotationClazz));
    }

    /**
     * 找出特定類上被特定註解標記的方法
     * @param objectClass 類的Class
     * @param annotationClass 註解的Class
     * @return 被annotationClass標記的方法
     * @throws Exception 沒有方法上面有annotationClass的註解
     */
    public static Method getInterfaceMethod(Class<?> objectClass, Class<? extends Annotation> annotationClass) throws Exception {
        Method[] declaredMethods = objectClass.getDeclaredMethods();
        for (Method declaredMethod : declaredMethods) {
            Annotation[] declaredAnnotations = declaredMethod.getDeclaredAnnotations();
            for (Annotation declaredAnnotation : declaredAnnotations) {
                if (declaredAnnotation.annotationType().equals(annotationClass)) {
                    return declaredMethod;
                }
            }
        }

        throw new Exception("沒有含有 " + annotationClass.getName() + " 註解的方法");
    }

    /**
     * 對代理類上相應的函數調用轉化爲被特定註解標記的函數調用
     */
    private static class InterfaceHandler implements InvocationHandler {
        private Object object;
        private Class annotationClazz;

        public InterfaceHandler(Object object, Class annotationClazz) {
            this.object = object;
            this.annotationClazz = annotationClazz;
        }


        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            if (method.getName().toLowerCase().endsWith(annotationClazz.getSimpleName().toLowerCase())) {
                Method interfaceMethod = getInterfaceMethod(object.getClass(), annotationClazz);
                return interfaceMethod.invoke(object, args);
            }
            throw new Exception("未實現函數");
        }
    }

}


/**
 * 待實現的接口
 */
interface Playable {
    void play();
}

/**
 * 在方法上加上Play註解即可實現Playable中的Play方法
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Play {
}

/**
 * 有註解標記函數的類,即我們希望通過註解實現接口的類
 */
class Lego {

    @Play
    void foo() {
        System.out.println("I can play");
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章