1、注解的定义与场景
1、定义
注解本身没有任何意义,单独的注解就是一种注释,他需要结合其他,如:反射、插装等技术才有意义。
Java注解(Annotation)又称Java标注,是JDK1.5引入的一种注释机制。是元数据的一种形式,提供了关于程序但不属于程序本身的数据。注解对它们注解的代码的操作没有直接影响。
我们通过@interface 来实现一个自定义注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Lich {
int value();
String id();
}
我们定义这个注解有两个元素,id 跟value,我们可以给她增加一个默认值 在后边增加一个。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.SOURCE)
public @interface Lich {
int value() default 1;
String id() default "努力学习";
}
2、元注解
在定义注解时,注解类也能够使用其他注解声明。对注解类型进行注解的注解类,我们称之为meta-annotation(元注解)。声明的注解允许作用于哪些节点使用@Target声明;保留级别由@Retention声明。其中保留级别如下:
- RetentionPolicy.SOURCE 标记的注解仅保留在源级别中,并被编译器忽略。
- RetentionPolicy.CLASS 标记的注解在编译时由编译器保留,但Java虚拟机会忽略。
- RetentionPolicy.RUNTIME 标记的注解由JVM保留,因此运行环境可以使用它。
SOURCE<CLASS<RUNTIME,即CLASS包含了SOURCE;RUNTIME包含了SOURCE、CLASS。
以上代码中,@Target,@Retention就是我们的元注解。注解上面的注解。@Target 用来指示我们Lich注解能作用在那个范围上,是类上,还是成员属性上面,类上面等。如果注解没有设定默认值,则需要设置值
@Lich(value=1,id="天天向上")
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
我们可以查看字节码
3、应用场景
- 源码
APT,在编译期能够获得注解与注解声明的类包括类中所有的成员信息,一般用于生成额外的辅助类。
- 字节码
字节码增强,在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。((在在字节码中写代码)
- 运行时
在程序运行期间,通过反射技术动态获取其注解与其元素,从而完成不同的逻辑判断。
4.Android注解语法检查
在Android中,我们需要设计接口以供使用者调用时,如出现需要对入参进行限定,如限定为资源ID、布局ID等类型参数,将参数类型直接给int即可。然而我们也可以利用Android为我们提供的语法检查注解,来辅助进行更为直接的参数类型检查与提示。
参数限制为:图片资源ID。
同时我们也可以利用@Intdef来定义自己的入参类型检查。
private static final int SUNDAY=0;
private static final int MONDAY=1;
@IntDef({SUNDAY,MONDAY})
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.SOURCE)
@interface WekDay{
}
public static void setCurrentDay(@WekDay int currentDay){
mCurrentIntDay=currentDay;
}
@Intdef 语法检查是由IDE来检查
2、反射
一般情况下,我们使用某个类时必定知道它是什么类,是用来做什么的,并且能够获得此类的引用。于是我们直接对这个类进行实例化之后对这个类对象进行操作。
反射是一开始并不知道我要初始化的对象是什么,自然也无法使用new关键字来创建对象。这个时候,我们使用JDK提供的反射API进行反射调用。反射就是运行状态中,对任意一个类都能够知道这个类所有的属性和方法;对任意一个对象都能够调用它的任意方法和属性;并能改变它的属性。是Java被视为动态语言的关键。
- 如何运行
.java->javac->.class
采集到所有的注解信息->Element->注解处理程序,这个过程不需要我们去处理,只需要javac去处理就好
注解+反射:自动完成findViewById
新建注解类
/**
* 版本:1.0
* 创建日期:2020-05-21 00:04
* 描述:
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface InjectView {
@IdRes int value();
}
通过反射,对view进行注入
getFields():获取自己+父类的成员(不包括private)
getDeclaredFields():只能获取自己的成员(不包括父类)
/**
* 版本:1.0
* 创建日期:2020-05-20 23:59
* 描述:
*/
public class InjectUtils {
public static void injectView(Activity activity){
Class<? extends Activity>cls=activity.getClass();
Field[] declaredFields = cls.getDeclaredFields();
for (Field f:declaredFields) {
//判断属性是否被InjectView注解声明
if (f.isAnnotationPresent(InjectView.class)){
InjectView injectView= f.getAnnotation(InjectView.class);
int id =injectView.value();
View view = activity.findViewById(id);
//反射设置属性的值
f.setAccessible(true);//设置访问的权限 允许操作private的属性
try {
f.set(activity,view);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
对结果进行验证
public class MainActivity extends AppCompatActivity {
@InjectView(R.id.tv_hello)
TextView textView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
InjectUtils.injectView(this);
textView.setText("你好哇,同学");
}
}
反射的一些方法与属性:
3、Type体系
- TypeVariable 泛型类型变量。可以泛型上下限等信息。
- ParameterizedType 具体泛型类型,可以获得元数据中泛型签名类型(泛型真是类型)
- GenericArrayType 当需要描述的类型是泛型类的数组时,比如List[],Map[],此接口会作为Type的实现。
- WildcardType 通配符泛型,获得上下限信息;
TypeVariable
/**
* 版本:1.0
* 创建日期:2020-05-21 22:36
* 描述:
* TypeVariable 泛型信息在编译时会被转换成一个特定类型,而TypeVariable 就是用来反射JVM编译该泛型信息的
* TypeVaiable 就是<T> <C extends Collection>中的变量 T、C本身:它有如下方法
* Type[] getBounds():获取泛型的上边界,若未明确声明上边界则默认为Object
* D getGenericDeclaration():获取该声明变量的类型
* String getName():获取在源码中定义的名字
* 注意:
* 类型变量在定义的时候只能用extends进行多边界限定,不能用super;
* 为什么边界是一个数组 ? 因为类型变量可以通过&进行多个上边界限定,因此上边界有多个
*
*/
public class TestType<K extends Comparable& Serializable,V> {
K key;
V value;
public static void main(String[] args) throws NoSuchFieldException {
//获取字段类型
Field fk =TestType.class.getDeclaredField("key");
Field fv =TestType.class.getDeclaredField("value");
TypeVariable keyType= (TypeVariable) fk.getGenericType();
TypeVariable valueType= (TypeVariable) fv.getGenericType();
//getName方法
System.out.println(keyType.getName());
System.out.println(valueType.getName());
//getGenericDeclaration方法
System.out.println(keyType.getGenericDeclaration());
System.out.println(valueType.getGenericDeclaration());
//getBounds 方法
System.out.println("K的上界:"); //有两个
for (Type type:keyType.getBounds()) { // interface java.lang.Comparable
// interface java.io.Serializable
System.out.println(type);
}
System.out.println("V的上界");
for (Type type:valueType.getBounds()) { //没有明确上界的,默认上界是 Object
System.out.println(type); //class java.lang.Object
}
}
}
ParameterizedType:
/**
* 版本:1.0
* 创建日期:2020-05-21 22:57
* 描述:具体的泛型类型,如 Map<String,String>
* 有如下方法:
* <p>
* Type getRawType():返回承载该泛型信息的对象,如上面那个Map<String,String> 承载泛型的对象是Map
* Type[] getActualTypeArguments() 返回实际泛型类型列表,如上面那个Map<String,String>实际泛型列表中有两个元素 ,都是String
*/
public class TestType {
Map<String,String> map;
public static void main(String[] args) throws NoSuchFieldException {
Field f=TestType.class.getDeclaredField("map");
System.out.println(f.getGenericType());//java.util.Map<java.lang.String, java.lang.String>
ParameterizedType pType= (ParameterizedType) f.getGenericType();
System.out.println(pType.getRawType());//interface java.util.Map
for (Type type:pType.getActualTypeArguments()
) {
//class java.lang.String
//class java.lang.String
System.out.println(type);
}
}
}
GenericArrayType :
/**
* 版本:1.0
* 创建日期:2020-05-21 23:06
* 描述:GenericArrayTyoe
* 泛型数组,组成数组的元素中有泛型则实现了该接口:它的组成元素是ParameterizedType 或 TypeVariable类型 ,它只有一个方法
* <p>
*Type getGenericComponentType:返回数组的组成对象
*/
public class TestType<T> {
List<String>[] lists;
public static void main(String[] args) throws NoSuchFieldException {
Field f=TestType.class.getDeclaredField("lists");
GenericArrayType genericArrayType= (GenericArrayType) f.getGenericType();
System.out.println(genericArrayType.getGenericComponentType());//java.util.List<java.lang.String>
}
}
WildcardType :
/**
* 版本:1.0
* 创建日期:2020-05-07 07:19
* 描述: 该接口表示通配符泛型,比如?extends Number 和 ?super Integer 它有如下方法
* Tyoe[] getUpperBounds():获取泛型变量的上界
* Type[] getLowerBounds() :获取泛型变量的下界
* 注意:
* 现阶段通配符只接受一个上边界或者下边界,返回数组是为了以后的扩展,实际上现在返回的数组的大小是1
*
*
*/
public class TestType {
private List<? extends Number> a;//上限
private List<? super String> b;//下限
public static void main(String[] args) throws NoSuchFieldException {
Field fieldA=TestType.class.getDeclaredField("a");
Field fieldB=TestType.class.getDeclaredField("b");
//先拿到类型范围
ParameterizedType pTypeA= (ParameterizedType) fieldA.getGenericType();
ParameterizedType pTypeB= (ParameterizedType) fieldB.getGenericType();
//再从泛型里边拿到通配符
WildcardType wTypeA= (WildcardType) pTypeA.getActualTypeArguments()[0];
WildcardType wTypeB= (WildcardType) pTypeB.getActualTypeArguments()[0];
//方法测试
System.out.println("测试:"+wTypeA.getUpperBounds()[0]);
// System.out.println("测试:"+wTypeA.getLowerBounds()[0]);
System.out.println("测试:"+wTypeB.getLowerBounds()[0]);
System.out.println("测试:"+wTypeB.getUpperBounds()[0]);
//看看通配符是什么,发音结果为 ?extends java.lang.Number
System.out.println(wTypeA);
}
}
泛型与反射的结合运用
public class TypeReference<T> {
Type type;
T t;
protected TypeReference() {
//获得泛型类型
Type genericsSuperclass=getClass().getGenericSuperclass();
ParameterizedType parameterizedType= (ParameterizedType) genericsSuperclass;
//因为泛型可定义多个A<T,E...>所以是个数组
Type[] actualTypeArguements=parameterizedType.getActualTypeArguments();
type=actualTypeArguements[0];
}
public Type getType(){
return type;
}
}
对数据进行解析
public class Deserialize {
static class Respone<T>{
T data;
int code;
String messge;
@Override
public String toString() {
return "Response{"+
"data="+data+
",code="+code+
",message="+messge+"\'"+
"}";
}
public Respone(T data, int code, String messge) {
this.data = data;
this.code = code;
this.messge = messge;
}
}
static class Data{
String result;
public Data(String result) {
this.result = result;
}
@Override
public String toString() {
return "Data{"+"result="+result+"}";
}
}
static class ChildTypeRefrence{
Respone<Data> t;
}
public static void main(String[] args) {
Respone<Data> dataRespone=new Respone<>(new Data("数据"),1,"成功");
Gson gson=new Gson();
String json=gson.toJson(dataRespone);
System.out.println(json);
System.out.println(dataRespone.toString());
//反序列化
/**
* 有花括号,是代表匿名内部类,创建一个匿名内部类的实例对象
* 没花括号:创建实例对象
*/
Type type=new TypeReference<Respone<Data>>(){}.getType();
Type type1=new TypeToken<Respone<Data>>(){}.getType();
System.out.println("type是:"+type);
Respone<Data> respone=gson.fromJson(json,type);
System.out.println("获取返回来的类:"+respone.data.getClass());
}
}