Java中的自定义注解
一、什么是注解?
An annotation is a form of metadata, that can be added to Java source code. Classes, methods, variables, parameters and packages may be annotated. Annotations have no direct effect on the operation of the code they annotate.
首先以上是官方的描述,
翻译过来的意思就是:注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。
Annontation是Java5开始引入的新特征,中文名称叫注解。
注解是一种元数据形式。即注解是属于java的一种数据类型,和类、接口、数组、枚举类似。
它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观、更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
Java注解是附加在代码中的一些元信息,主要用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。
二、自定义注解的语法
新建一个自定义注解
当我们使用的时候直接@加上注解名称即可
自定义注解成员属性
注意后面的圆括号不要写丢;这是一个必要特殊的语法。
这个时候要再使用自定义注解的时候就必须给成员属性赋值,
成员属性默认值;可以自己给定默认值,默认值要与前面的类型相对应。
当我们使用自定义注解的时候可以什么都不用写,系统会自动给我们添加上一句话。把我们的属性赋予一个默认值,但是这句话其实是看不到的。
可以作用在类上,可以作用在成员属性上等,因为我们并没有定义它可以作用到哪里。
三、反射注解
在了解反射注解之前,先来看看什么是元注解,元注解就是为其他注解做注解的,就是注解的注解;元注解有四个:
@Decumented : 指示某一类型的注释通过javadoc和类似的默认工具进行文档化。
@Inherited : 指示注释类型被自动继承。
@Retention : 指示注释类型的注释要保留多久。(注解可以保留多久)
@Target : 指示注释类型所适用的程序元素的种类。(注解适用于什么范围)
在这里的话主要掌握后面两个注解就可以。
@Retention:有一个参数,这个参数是一个枚举,这个枚举叫做RetentionPolicy枚举,有三个值(①SOURCE 不编译Annotation到类文件中 ②CLASS 编译Annotation到类文件中,运行时不加载 ③RUNTIME 在运行时加载到JVM中)
生命周期类型 | 描述 |
---|---|
RetentionPolicy.SOURCE | 编译时被丢弃,不包含在类文件中 |
RetentionPolicy.CLASS | JVM加载时被丢弃,包含在类文件中,默认值 |
RetentionPolicy.RUNTIME | 由JVM 加载,包含在类文件中,在运行时可以被获取到 |
注解类似注释的一个效果,我们可以选择不将这个注释编译到class当中(SOURCE)。class有这个注解,但是运行时看不见(CLASS) 。运行的时候也能看到这个注解(RUNTIME)。最后一个是我们重点要掌握的。是反射注解的前提条件。
@Target :用于描述注解的使用范围,该注解可以使用在什么地方
Target类型 | 描述 |
---|---|
ElementType.TYPE | 应用于类、接口(包括注解类型)、枚举 |
ElementType.FIELD | 应用于属性(包括枚举中的常量) |
ElementType.METHOD | 应用于方法 |
ElementType.PARAMETER | 应用于方法的形参 |
ElementType.CONSTRUCTOR | 应用于构造函数 |
ElementType.LOCAL_VARIABLE | 应用于局部变量 |
ElementType.ANNOTATION_TYPE | 应用于注解类型 |
ElementType.PACKAGE | 应用于包 |
备注:例如@Target(ElementType.METHOD),标志的注解使用在方法上,但是如果我们把这个注解标志在类上,就会有报错
之前我们学反射的时候学到了三个类,Constructor(构造方法类)、Field(成员属性类)、Method(成员方法类),这三个类都提供了三个可以反射注解的方法;
①isAnnoationPresent(Class annotationClass):(查看类成员是否被某一个注解注解过,即查看是否添加了指定的注解。如果它包含某一个注解,那么就返回一个true,否则就返回一个false)
②getAnnoation(Class annoationClass):获取指定的注解。
③getAnnoations():获取所有注解的数组。
如果我们要将类中的注解反射出来,需要有一个前提,就是元注解@Retention(RetentionPolicy.RUNTIME),将我们的注解放到Java虚拟机当中。那反射注解有什么作用呢?下面来用一个例子演示一下。
为手机类成员属性添加注解,并反射这些注解。
我们写代码这样写
public class CellPhone {
public String brdMdl;//品牌型号
public double price;//价格
public String batteryInter;//电池接口
public String producedArea;//手机厂商
}
一个类中有许多的属性,我们会给这些类写注释,但是这样写会有一点缺陷,当程序运行的时候,我们的注释会被屏蔽掉,我们根本看不到的,如果我们想要在程序运行的时候也能看到这些注释的话,我们就需要用到注解,我们通过反射注解就可以程序运行时它的那些注释全部都取出来。
注解@PhoneAnnotation代码如下:
package com.allen.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)//此注解只可以用在成员属性上
@Retention(RetentionPolicy.RUNTIME)//此注解可以被反射,把注解放在了Java虚拟机当中
public @interface PhoneAnnotation {
String remarks() default "";//备注
boolean enable() default true;//属性是否启用
}
类CellPhone的代码如下:
package com.allen.spring.entity;
import com.allen.spring.annotation.PhoneAnnotation;
public class CellPhone {
@PhoneAnnotation(remarks = "品牌型号")
public String brdMdl;//品牌型号
@PhoneAnnotation(remarks = "价格")
public double price;//价格
@Deprecated
@PhoneAnnotation(remarks = "电池接口",enable = false)//此属性不启用
public String batteryInter;//电池接口
@PhoneAnnotation(remarks = "手机厂商")
public String producedArea;//手机厂商
}
主函数调用:
package com.allen.spring.entity;
import com.allen.spring.annotation.PhoneAnnotation;
import java.lang.reflect.Field;
public class Demo {
public static void main(String[] args) {
Class c = CellPhone.class;
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
if (field.isAnnotationPresent(PhoneAnnotation.class)) {
System.out.println(field.getName() + "被注解过");
}
}
}
}
查看被注解过的值是什么:
反射注解的作用就是在程序运行时能获得类似注释的一个功能,这就是反射注解。
反射注解的前提是@Retention(RetentionPolicy.RUNTIME),它定义这个注解可以在运行时获得,也就是此注解可以被反射。