Java高级特性之注解

花门楼前见秋草,岂能贫贱相看老。这篇文章主要讲述Java高级特性之注解相关的知识,希望能为你提供帮助。

?
概念
java注解是JDK1.5的新特性,与注释比较类似,不同的是注释是给我们开发人员看的,注解是给代码看的,它是代码层面的解释说明。
注解的使用也很简单,语法规则:@注解名称,比如我们常见的“@Override”。
作用
①生成doc文档;
②使用反射对代码进行分析;
③编译检查。
JDK中预定义的一些注解:
①@Override: 检测方法是否是重写父类或父接口的;
②@Deprecated: 标识过时的内容;
③@SuppressWarnings: 压制警告,一般传入参数all,@SuppressWarnings("all")
自定义注解:
格式:
[元注解]
public @interface 注解名称{
属性列表;
}
eg.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface ZnkAnno {
String value();
}


ps:[ ] 表示可选。
【Java高级特性之注解】注解本质:
通过javap命令反编译class文件,可以发现注解的本质就是继承 java.lang.annotation.Annotation的接口。
Java高级特性之注解

文章图片

注解中的属性(其实就是接口中的抽象方法):
语法:
1> 属性的返回值必须是基本数据类型、String、Class、枚举、注解或者以上类型的数组;
2> 定义属性后,在使用注解时要给属性赋值,如果定义属性时使用default关键字给了属性默认值,则可以不做赋值;如果只有一个名称为value的属性,则value可以省掉,直接定义值即可;数组赋值时需要{},如果数组中只有一个值,则可省略{}。
Java高级特性之注解

文章图片

元注解
元注解就是用来解释说明注解的注解。
①@Target:描述注解能够作用的位置。
--ElementType常用取值:
  • TYPE:可以作用在类上;
  • FIELD:可以作用在属性上;
  • METHOD:可以作用在方法上。
PS:所有取值见下图。
Java高级特性之注解

文章图片

②@Retention:描述注解被保留的阶段(java代码SOURCE(源码阶段)、CLASS(字节码文件)、RUNTIME(运行时阶段)三个阶段)
-- @Retention(RetentionPolicy.RUNTIME) 表示当前被描述的注解会被保留到class字节码文件中,并会被JVM读取到
③@Documented:描述注解是否被抽取到api文档中
④@Inherited:描述注解是否被子类继承
注解的使用场景
上面我们已经了解到注解的保留级别包括SOURCE、CLASS、RUNTIME三个阶段,那我们根据保留级别不同,自然能想到注解的使用也存在不同场景。


级别




技术




备注




源码




APT




1.在编译期能够获取注解与注解声明的类,包括类中所有成员信息,一般用于生成额外的辅助类。
2.也可以用作语法检查。




字节码




字节码增强




在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。




运行时




反射




在程序运行期间,通过反射技术动态获取注解与其元素,从而完成不同的逻辑判定。


--源码级别的注解示例:
1> APT(Annotation Processor Tools)
Java高级特性之注解

文章图片

2> 语法检查:在android开发过程中,当我们需要设计接口供使用者调用时,如果需要对入参类型做限定,比如限定为资源ID、布局ID等类型参数,就可以通过@IdRes、@LayoutRes分别限定。同时我们可以利用@IntDef、@StringDef、@LongDef 定义自己的入参类型检查。
Java高级特性之注解

文章图片

--字节码级别的注解在热修复技术中会用到,这里暂时不做详细描述(关键我自己还没整明白{> -< })。
--运行时的注解主要是与反射结合做一些操作,比如我们常用的ButterKnife,最初就是通过注解加反射的方式实现的,我给出的git代码里面也有实现findViewById的案例,感兴趣的小伙伴可以瞄一眼。
Java高级特性之注解

文章图片

反射获取泛型真实类型(很少用到,了解即可)
当我们对泛型类进行反射时,需要拿到泛型信息来完成像Json反序列化的操作时,需要借助Type体系来完成。Type接口包含一个实现类Class和四个实现接口:
Java高级特性之注解

文章图片

我们开发过程中经常会有这样一种场景,我们请求后台接口,后台返回的数据类型可能是这样的:
{
"data":{
"name":"luffy",
"age":18,
"sex":"male"
},
"code":200,
"message":"查询成功"
}
我们会将后台返回的数据封装成一个Bean:

static class Response< T> {
T data;
int code;
String message;

public Response(T data, int code, String message) {
this.data = https://www.songbingjia.com/android/data;
this.code = code;
this.message = message;
}

@Override
public String toString() {
return "Response{" +
"data="https://www.songbingjia.com/android/+ data +
", code=" + code +
", message=" + message + \\ +
};
}
}


因为每个接口返回的data多数情况下类型是不同的,所以我们一般用泛型处理。比如现在某个接口返回的数据是
{
"name":"luffy",
"age":18,
"sex":"male"
}
我们将它封装成Bean:

static class Data {
String name;
int age;
String sex;

public Data(String name, int age, String sex) {
this.name = name;
this.age = age;
this.sex = sex;
}

@Override
public String toString() {
return "Data{" +
"name=" + name + \\ +
", age=" + age +
", sex=" + sex + \\ +
};
}
}


我们测试如上的数据是否可以进行反序列化:如下图所示,出现了ClassCastException。
Java高级特性之注解

文章图片

解决方案:

Type type = new TypeToken< Response< Data> > () {
}.getType();
Response< Data> response = gson.fromJson(result, type);


Java高级特性之注解

文章图片

我们来看看TypeToken里面的具体实现:
Java高级特性之注解

文章图片

我也按照这个思路试着实现了一下:

package com.luffy.reflect.Type;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

/**
* 作者宁科CSDN主页< /a> < p>
* 创建时间:2020/10/27 15:51< p>
* 描述:参考TypeToken 解决Json反序列化问题
*/
public class TypeRefrence< T> {
Type type;
T t;

protected TypeRefrence() {
//1.获得泛型类型
Type genericSuperclass = getClass().getGenericSuperclass();
System.out.println("genericSuperclass的类型是: " + genericSuperclass.getClass());
System.out.println("genericSuperclass ====== " + (genericSuperclass instanceof Class));
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
//2.因为泛型类型可以定义多个: MainActivity< T,E,K...> 所以返回是一个数组
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
type = actualTypeArguments[0];
}

public Type getType() {
return type;
}
}


Java高级特性之注解

文章图片

关于注解先讲这么多,觉得能get到好东西的小伙伴记得关注加点赞哟, 不懂的地方也可以评论区留言与我交流~


    推荐阅读