Hello注解与反射

注解的作用和意义

注解本身没有任何意义,单独的注解就是一种注释,它需要配合一些技术如反射、插桩才有意义。

注解Annotation称为Java标注,JDK1.5引入的一种注释机制。是元数据的一种形式,提供有关程序但不属于程序本身的数据。
注解对它们的注解的代码没有任何影响
package com.hello.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//元注解(注解上的注解)

//Target一对多 @Target({ElementType.TYPE,ElementType.METHOD})
@Target(ElementType.TYPE)
//Retention 保留级别RetentionPolicy.SOURCE 标记的注解仅保留在源码级别,编译器忽略
//Retention 保留级别RetentionPolicy.CLASS 标记的注解编译时保留在编译级别,JAVA虚拟机JVM忽略
//Retention 保留级别RetentionPolicy.RUNTIME 标记的注解保留在JVM级别,在运行时环境可以使用它

//CLASS包含了SOURCE  RUNTIME 包含了SOURCE、CLASS
@Retention(RetentionPolicy.SOURCE)
public @interface Hello {
    String value() default "aa";
}
级别技术说明
SOURCEAPT注解处理器在编译器能够获取注解与注解声明的类,包括类中所有成员,一般用于生成额外的辅助类
CLASS字节码增强在编译出Class后,通过修改Class以实现修改代码逻辑的目的。如各种 ORM 框架、Spring AOP、热部署
RUNTIME反射在运行期间,通过反射获取注解与元素,完成不同的逻辑判定

APT

META-INF/services/javax.annotation.processing.Processor文件夹下新建
javax.annotation.processing.Processor文件内容为注解处理器的全路径com.example.android.annotationtest.HelloProcessor
package com.example.android.annotationtest;

import java.util.Set;

import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Messager;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
//只关心那些注解
@SupportedAnnotationTypes("com.example.android.annotationtest.Hello")
@SupportedSourceVersion(value = SourceVersion.RELEASE_7)
public class HelloProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        Messager messager = processingEnv.getMessager();
        messager.printMessage(Diagnostic.Kind.NOTE, ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
        return false;
    }
}

插桩

插桩是将一段代码插入到另一段代码,或者替换另一段代码。字节码插桩顾名思义就是在我们编写的源码编译成字节码后,
在Android生成dex之前修改class文件,修改或者增强原有代码逻辑的操作。

反射

反射是一开始并不知道我要初始化的类的对象是什么,自然也无法使用new关键字来创建对象。这时候,我们
使用JDK提供的反射API进行反射调用。反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有
属性和方法;对任意一个对象,都能够调用它的任意方法和属性;并且改变它的属性,是java被视为动态语言的关键。

buffernife

采用反射+注解 实现findViewById
public class InjectUtils {

    public static void inject(Activity activity) {
        Class<? extends Activity> aClass = activity.getClass();
        //获得自己和父类的成员变量,不包括private
        //aClass.getFields();
        //只能获取自己的成员
        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field item : declaredFields) {
            //表明该属性打上InjectView标记
            if (item.isAnnotationPresent(InjectView.class)) {
                InjectView annotation = item.getAnnotation(InjectView.class);
                int value = annotation.value();
                View viewById = activity.findViewById(value);
                //设置访问权限
                item.setAccessible(true);
                try {
                    //赋值
                    item.set(activity, viewById);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}


@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InjectView {
    @IdRes int value();
}

public class TestInjectActivity extends AppCompatActivity {
    
    @InjectView(R.id.content)
    private TextView content;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        InjectUtils.inject(this);
        content.setText("hello");
    }
}

public static void main(String[] args) throws Exception {
        Class<?> cls = Class.forName("com.hello.testproxy.ActivityTaskManager");
        //IActivityTaskManager对应的子类
        Method method = cls.getMethod("getService");
        method.invoke(null);

        Field iActivityTaskManagerSingletonField = cls.getDeclaredField("iActivityTaskManagerSingleton");
        iActivityTaskManagerSingletonField.setAccessible(true);
        Object singleton = iActivityTaskManagerSingletonField.get(null);
        System.out.println("singleton:" + singleton);

        Class<?> aClass = Class.forName("com.hello.testproxy.Singleton");
        Field mInstance = aClass.getDeclaredField("mInstance");
        mInstance.setAccessible(true);
        Object o = mInstance.get(singleton);
        System.out.println("obj:" + o);

        Object proxy = Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("method>>>" + method.getName());
                return method.invoke(o, args);
            }
        });
        mInstance.set(singleton, proxy);
        ActivityTaskManager.getService().task();
        }
public class ActivityTaskManager {

    public static IActivityTaskManager getService() {
        return iActivityTaskManagerSingleton.get();
    }

    private static final Singleton<IActivityTaskManager> iActivityTaskManagerSingleton = new Singleton<IActivityTaskManager>() {
        @Override
        public IActivityTaskManager create() {
            return new TaskManager();
        }
    };
}

public abstract class Singleton<T> {
    private T mInstance;

    public abstract T create();

    public final T get() {
        synchronized (this) {
            if (mInstance == null) {
                mInstance = create();
            }
            return mInstance;
        }
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值