注解本身没有任何意义,单独的注解就是一种注释。它需要结合如 反射、插桩等技术才有意义
Java注解(Annotation)又称Java标注,是元数据的一种形式,提供有关程序但不属于程序本身的数据注解对他们注解的代码没有直接影响。
@Target/@Retention元注解:
元注解:注解上的注解 指示当前声明的注解可以作用那些位置
@Target(ElementType.TYPE) 如果没有指定@Target的话 默认全部(TYPE->类 属性 METHOD->方法 构造方法 FIELD->属性 PARAMETER->参数)可以指示多个 ElementType.FIELD,ElementType.PARAMETER
@Retention:保留级别 保留这个注解到什么时候
@Retention(RetentionPolicy.SOURCE)(SOURCE->仅保留到源码阶段(javac编译成class之后就会被抹除),CLASS->保留在class文件中 但是在JVM加载class文件时会被忽略,RUNTIME->运行时 由JVM保留运行结果让我们获取这个注解 反射技术)
SOURCE<CLASS<RUNTIME 即class包含了SOURCE,RUNTIME包含了SOURCE,CLASS
public @interface Lance{
//元素 可以指定基本数据类型 注解类型 引用类型
String value() default "";
}
@Target
注解标记另一个注解,以限制可以应用注解的 Java 元素类型。目标注解指定以下元素类型之一作为其值:
@Lance("")
public class MainActivity extends AppcompatActivity{
}
APT(Annotation Processor Tools) 注解处理器:
源码级别,在编译期RetentionPolicy.SOURCE能够获取注解与注解声明的包括类中的所有成员信息,一般用于生成额外的辅助类。
JVM虚拟机不认识java文件,由javac编译成.class文件
.java->javac->.class
javac解析要编译的java类 就要采集到所有的注解信息 然后将所有注解信息包装成节点->Element->由javac调起注解处理器
由javac调用注解处理器 不用我们手动调用 只需要给javac指明要处理的注解处理程序
直接收特定注解
@SupportedAnnotationTypes("com.enjoy.annotation.Lance")
AbstractProcessor:JDK给我们提供的 LanceProcessor就是一个注解处理程序 javac会调用里面的process方法
public class LanceProcessor extends AbstractProcessor{
@Override
public boolean process(Set<? extends TypeElement> set,RoundEnvironment roundEnvironment){
//AbstractProcessor内部属性 processingEnv
Messager messager = processingEnv.getMessager();
messager.printMessage(Dialogstic.Kind.NOTE,"========");
//会执行两次 可能与返回值有关
return false;
}
}
名字是固定的 必须是下面
新建Direcory->resources/META-INF.services/javax.annotation.processing.Processor
注解处理程序的全类名
com.enjoy.compiler.LanceProcessor
在字节码中写代码
.class->格式 数据按照特定的方式记录与排列
.class->IO->byte[]->不能乱改
反编译后的class文件
public class MainActivity extends AppcompatActivity{
public MainActivity(){
}
@InjectTime
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
this.setContentView(2131296285);
this.a();
}
@InjectTime
void a(){
try{
Thread.sleep(2000L);
}catch(InterruptedException var2){
var2.prointStackTrace();
}
}
}
想要在@InjectTime注解的方法上第一行和最后一行都插入当前系统时间并算出两者相减的时间
注解的意义是 你是都要对这个方法进行增强
运行时级别,在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判定。
反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和
方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。是Java被视为动态语言的关键。
Java反射机制主要提供了以下功能:
反射始于Class,Class是一个类,封装了当前对象所对应的类的信息。一个类中有属性,方法,构造器等,比如说
有一个Person类,一个Order类,一个Book类,这些都是不同的类,现在需要一个类,用来描述类,这就是
Class,它应该有类名,属性,方法,构造器等。Class是用来描述类的类
获取class对象的三种方式
public static Class<?> forName(String className)
Class<?> kclass = int.class;
Class<?> classInt = Integet.TYPE;
StringBuilder str = new StringBuilder("123");
Class<?> kclass = str.getClass();
一般的 我们用instanceof关键字来判断是否为某个类的实例,同时我们也可以借助反射中Class对象的 isInstance()方法来判断是否为某个类的实例 它是一个native方法:
public native boolean isInstance(Object obj);
判断是否为某个类的类型
public boolean isAssignableForm(Class<?> cls)
通过反射来生成对象主要有两种方式
Class<?> c = String.class;
Object str = c.newInstance();
//获取String所对应的Class对象
Class<?> c= String.class;
//获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//根据构造器创建实例
Object obj = constructor.newInstance("2333");
System.out.println(obj);
得到构造器的方法
Constructor getConstructor(Class[] params) -- 获得使用特殊的参数类型的public构造函数(包括父类)
Constructor[] getConstructors() -- 获得类的所有公共构造函数
Constructor getDeclaredConstructor(Class[] params) -- 获得使用特定参数类型的构造函数(包括私有)
Constructor[] getDeclaredConstructors() -- 获得类的所有构造函数(与接入级别无关)
获取类构造器的用法与上述获取方法的用法类似。主要是通过Class类的getConstructor方法得到Constructor类的
一个实例,而Constructor类有一个newInstance方法可以创建一个对象实例:
public T newInstance(Object ... initargs)
获取字段信息的方法
Field getField(String name)--获取命名的公共字段+父类成员 (不包括private只能是public)
Field[] getFields()--获取类的公共字段
Field getDeclaredField(String name)--获取类声明的命名的字段
Field[] getDeclaredFields()--获取类声明的所有字段 不包括父类 所有作用域
获取方法信息的方法
Method getMethod(String name,Class[] params)--使用特定的参数类型 获得命名的公共方法
Method[] getMethods() --获得类的所有公共方法
Method getDeclaredMethod(String name,Class[] params)--使用特定的参数类声明的命名的方法 Method[] getDeclaredMethods()--获得类声明的所有方法
当我们从类中获取了一个方法后,我们可以用invoke方法来调用这个 invoke方法原型为
public Object invoke(Obejct obj,Object ... args)
数组在java里是比较特殊的一种类型。它可以赋值给一个Object Reference其中的Array类为java.lang.reflect.Array类 我们通过Array.newInstance()创建数组对象 它的原型是
public static Object newInstance(Class<?> componentType,int length);
当我们对一个泛型类型进行反射时,需要得到泛型中的真实数据类型,来完成如json反序列化的操作,此时需要通过 type体系来完成,type接口包含了一个实现类(class对象)和四个实现接口,
public final class Class implements Type{
}
他们分别是:
Json反序列化操作
public class Deserialize{
static class Response<T>{
T data;
int code;
String message;
public Response(T data,int code,String message){
this.data = data;
this.code = code;
this.message = message;
}
}
static class Data{
String result;
public Data(String result){
this.result = result;
}
}
}
//test
public static void main(String[] args){
Response<Data> dataResponse = new Response(new Data("数据"),1,"成功");
Gson gson = new Gson();
String json = gson.toJson(dataResponse);
//反序列化
Type type = new TypeToken<Response<Data>>(){}.getType();
Response<Data> response = gson.fromJson(json,type);
System.out.println(response.data.getClass());
//自定义一个TypeToken 为什么人家写protecte 不同的包下protected必须加{}
//有花括号: 代表匿名内部类 没有花括号就是对象 对象没有记录Response东西 可在字节码中查看
//加{}是 class 匿名内部类 编译后会多一个 类名$1.class 匿名内部类保存了泛型的具体类型
Type type = TypeRefrence<Response<Data>>(){}.getType();
}
static class TypeRefrence<T>{
Type type;
public TypeRefrence(){
//获得泛型类型
Type genericSuperclass = getClass().getGenericSuperclass();
ParameterizedType type = (ParamterizedType) genericSuperclass;
//可以有多个泛型
Type[] actualTypeArguments = type.getActualTypeArguments();
type = actualTypeArguments[0];
}
public Type getType(){
return type;
}
}
>>>>>>>>>>TypeToken源码解析
public class TypeToken<T>{
final Class<? super T> rawType;
final Type type;
final int hashCode;
protected TypeToken(){
this.type = getSuperclassTypeParameter(this.getClass());
this.rawType = Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
}
static Type getSuperclassTypeParameter(Class<?> subclass){
//获取当前对象的泛型类型
Type superclass = subclass.getGenericSuperclass();
if(superclass instanceof Class){
throw new RuntimeException("Missing type parameter");
}else{
//具体泛型类型
ParameterizedType parameterized = (ParameterizedType) superclass;
return Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
}
}
public static void injectView(Activity activity){
//当前activity对应的class对象
Class<? extends Activity> cls = activity.getClass();
cls.getSuperclass();//父类的class对象
//获得此类所有的成员
Field[] declaredFields = cls.getDeclaredFields();
for(Field declaredField : declaredFields){
if(declaredField.isAnnotationPresent(InjectView.class)){//是否被该注解声明
InjectView injectView = declaredField.getAnnotation(InjectView.class);
//获得注解中设置的id
int id = injectView.value();
View view = activity.findViewById(id);//拿到当前view
//反射设置 属性的值
declaredField.setAccessible(true);//允许访问 如果为private 设置访问权限
try{
//反射赋值 declaredField->TextView 吧view的值赋给给MainActivity中的Tv
declaredField.set(activity,view);
//设置activity中的TextView吧值设为view
}catch(IllegalAccessException e){
e.printStackTrace();
}
}
}
}
打标签
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.Field)
public @interface InjectView{
@IdRes int value();
}
使用
@InjectView(R.id.textView)
TextView tv;
getIntent()拿到上一个页面传递过来的数据
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired{
String value() default "";
}
public static void injectAutowired(Activity activity){
Class<? extends Activity> cls = activity.getClass();
//获得数据
Intent intent = activity.getIntent();
Bundle extras = intent.getExtras();
if(extras == null){
return;
}
//获得此类所有成员变量
Field[] declaredFields = cls.getDeclaredFields();
for(Field field:declaredFields){
if(field.isAnnotationPresent(Autowired.class)){
Autowired autowired = field.getAnnotation(Autowired.class);
//获得key
String key = TextUtils.isEmpty(autowired.value())?field.getName():autowired.value();
if(extras.containsKey(key)){
Object obj = extras.get(key);
//Parcelable数组类型不能直接设置 其他都可以
//获得单个元素类型
Class<?> componentType = field.getType().getComponentType();
//当前属性是数组并且是Parcelable(子类)数组
if(field.getType().isArray() && Paracelable.class.isAssignableFrom(componentType)){
Object[] objs = (Object[]) obj;
//创建对应类型的数组并由objs拷贝
Object[] objects = Arrays.copyOf(objs,objs.length,(Class<? extends Object[]>) field.getType());
obj = objects;
}
field.setAccessible(true);
try{
field.set(activity,obj);
}catch(IllegaAccessException e){
e.printStackTrace();
}
}
}
}
}