java注解怎么写_java注解
写在前⾯
现在的java主流框架中,注解⽆处不在,因此我们完全有必要搞明⽩注解到底是什么。如何理解注解,它到底是怎么起作⽤的。
注解的定义
java是这样定义注解的:Java 注解⽤于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执⾏,但也有⼀些类型的注解实际上可以⽤于这⼀⽬的。什么⼜是元数据的呢?说⽩了就是描述数据的数据,既然注解被称为元数据,具有描述作⽤,那么我们是不是可以把注解理解成标签来使⽤呢。我觉得学习注解,应该着重理解注解的作⽤是什么?在⽇常⼯作中是如何使⽤的即可,⼀般⽆需我们定义和解释注解,⽽注解解释器,也就是读取注解的类在框架中多数是隐藏起来的,除⾮阅读源码,否则根本看不到。
⽇常开发中新建Java类,我们使⽤class、interface⽐较多,⽽注解和它们⼀样,也是⼀种类的类型,他是⽤的修饰符为 @interface
格式
public @interface 注解名称{
属性列表;
}
分类
注解可分为JDK内置注解和⾃定义注解
内置的注解:
Java 定义了⼀套注解,共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。
作⽤在代码的注解是
@Override - 检查该⽅法是否是重写⽅法。如果发现其⽗类,或者是引⽤的接⼝中并没有该⽅法时,会报编译错误。
@Deprecated - 标记过时⽅法。如果使⽤该⽅法,会报编译警告。
@SuppressWarnings - 指⽰编译器去忽略注解中声明的警告。
作⽤在其他注解的注解(或者说 元注解)是:jdk怎么使用
@Retention - 标识这个注解怎么保存,是只在代码中,还是编⼊class⽂件中,或者是在运⾏时可以通过反射访问。
@Documented - 标记这些注解是否包含在⽤户⽂档中。
@Target - 标记这个注解应该是哪种 Java 成员。
@Inherited - 标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何⼦类)
从 Java 7 开始,额外添加了 3 个注解:
@SafeVarargs - Java 7 开始⽀持,忽略任何使⽤参数为泛型变量的⽅法或构造函数调⽤产⽣的警告。
@FunctionalInterface - Java 8 开始⽀持,标识⼀个匿名函数或函数式接⼝。
@Repeatable - Java 8 开始⽀持,标识某注解可以在同⼀个声明上使⽤多次。
⾃定义注解:
⾃定义注解就是⾃⼰编写的注解,⽽框架中所写的那些注解也可称为⾃定义注解,也是通过被元注解标记⽽写出来的注解。
注解的作⽤
如果说注释是写给⼈看的,那么注解就是写给程序看的。它更像⼀个标签,贴在⼀个类、⼀个⽅法或者字段上。它的⽬的是为当前读取该注解的程序提供判断依据。
要牢记,只要⽤到注解,必然存在三⾓关系:定义注解,使⽤注解,注解解析。如下图:
往往我们要做的是使⽤注解,⽽注解的定义跟解析⼀般框架都帮我们做好了。
注解的使⽤
1.⾃定义注解怎么写?
在编写⾃定义注解之前,我们必须先了解元注解
以下部分摘⾃简书(若 | 寒),对元注解的解析做的⾮常不错。
上⾯定义中提到,元注解可以理解为注解的注解,它是作⽤在注解中,⽅便我们使⽤注解实现想要的功能。元注解分别有@Retention、
@Target、 @Document、 @Inherited和@Repeatable(JDK1.8加⼊)五种。
@Retention
Retention英⽂意思有保留、保持的意思,它表⽰注解存在阶段是保留在源码(编译期),字节码(类加载)或者运⾏期(JVM中运⾏)。在
@Retention注解中使⽤枚举RetentionPolicy来表⽰注解保留时期
@Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码⽂件中不包含
@Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码⽂件中存在,但运⾏时⽆法获得
@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码⽂件中存在,jvm虚拟机在加载class⽂件后仍然存在,在运⾏时可以通过反射获取到
如果我们是⾃定义注解,则通过前⾯分析,我们⾃定义注解如果只存着源码中或者字节码⽂件中就⽆法发挥作⽤,⽽在运⾏期间能获取到注解才能实现我们⽬的,所以⾃定义注解中肯定是使⽤ @Retention(RetentionPolicy.RUNTIME)
@Target
Target的英⽂意思是⽬标,这也很容易理解,使⽤@Target元注解表⽰我们的注解作⽤的范围就⽐较具体了,可以是类,⽅法,⽅法参数变量等,同样也是通过枚举类ElementType表达作⽤类型
@Target(ElementType.TYPE) 作⽤接⼝、类、枚举、注解
@Target(ElementType.FIELD) 作⽤属性字段、枚举的常量
@Target(ElementType.METHOD) 作⽤⽅法
@Target(ElementType.PARAMETER) 作⽤⽅法参数
@Target(ElementType.CONSTRUCTOR) 作⽤构造函数
@Target(ElementType.LOCAL_VARIABLE)作⽤局部变量
@Target(ElementType.ANNOTATION_TYPE)作⽤于注解(@Retention注解中就使⽤该属性)
@Target(ElementType.PACKAGE) 作⽤于包
@Target(ElementType.TYPE_PARAMETER) 作⽤于类型泛型,即泛型⽅法、泛型类、泛型接⼝ (jdk1.8加⼊)
@Target(ElementType.TYPE_USE) 类型使⽤.可以⽤于标注任意类型除了 class (jdk1.8加⼊)
⼀般⽐较常⽤的是ElementType.TYPE类型
@Documented
Document的英⽂意思是⽂档。它的作⽤是能够将注解中的元素包含到 Javadoc 中去。
@Inherited
Inherited的英⽂意思是继承,但是这个继承和我们平时理解的继承⼤同⼩异,⼀个被@Inherited注解了的注解修饰了⼀个⽗类,如果他的⼦类没有被其他注解修饰,则它的⼦类也继承了⽗类的注解。
@Repeatable
Repeatable的英⽂意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作⽤⼀个对象多次,但是每次作⽤注解⼜可以代表不同的含义。
注解属性类型
注解属性类型可以有以下列出的类型
基本数据类型
String
枚举类型
注解类型
Class类型
以上类型的⼀维数组类型
2.如何解析使⽤注解?
前⾯说到了注解如何定义,在哪使⽤等,其他注解的关键,是获取注解中的属性值,这才是使⽤注解的真正⽬的。前⾯也说到,要想使⽤⾃定义的注解,必须要使⽤@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码⽂件中存在,jvm虚拟机在加载class⽂件后仍然存在,在运⾏时可以通过反射获取到,⽽获取注解的主要⼿段就是通过反射来获取。其中有三个主要的⽅法
/**是否存在对应 Annotation 对象*/
public boolean isAnnotationPresent(Class extends Annotation> annotationClass) {
return GenericDeclaration.super.isAnnotationPresent(annotationClass);
}
/**获取 Annotation 对象*/
public A getAnnotation(Class annotationClass) {
return (A) annotationData().(annotationClass);
}
/**获取所有 Annotation 对象数组*/
public Annotation[] getAnnotations() {
Array(annotationData().annotations);
}
⼀个⼩demo:
MyAnnotation.java
@Target({ElementType.TYPE,ElementType.METHOD})
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value() default "apang";
int num() default 99;
}
TestAnnotation.java
@MyAnnotation(value = "注解⽤在类上")
public class TestAnnotation {
@MyAnnotation()
public void test1() {
/
/使⽤默认值
}
@MyAnnotation(value = "注解⽤在⽅法上",num = 88)
public void test2() {
//使⽤⾃定义值
}
}
MyAnnotationProcessor.java
public class MyAnnotationProcessor {
public static void main(String[] args) throws Exception {
//获取类对象
Class clazz1 = TestAnnotation.class;
MyAnnotation annotation = Annotation(MyAnnotation.class);
System.out.println(annotation);
System.out.println(annotation.value());
System.out.println(annotation.num());
Method[] methods = DeclaredMethods();
for (Method m : methods) {
Annotation an = m.getAnnotation(MyAnnotation.class);
System.out.println(an);
System.out.println(((MyAnnotation) an).value());
System.out.println(((MyAnnotation) an).num());
}
}
}
输出
>>> @com.apang.annotation.MyAnnotation(value=注解⽤在类上, num=99) >>> 注解⽤在类上
>>> 99
>>> @com.apang.annotation.MyAnnotation(value=注解⽤在⽅法上, num=88) >>> 注解⽤在⽅法上
>>> 88
>>> @com.apang.annotation.MyAnnotation(value=apang, num=99)
>>> apang
>>> 99

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。