Java注解(Annotion)
定义一个注解
package org.zj;
public @interface TestAnnotation {
}
你会发现,这个注解怎么和接口一样,实际上,注解就是一个继承Annotation的接口,我们可以反编译上边的代码看一下注解的本质
public interface org.zj.TestAnnotation extends java.lang.annotation.Annotation {
}
如何使用注解
package org.zj;
@TestAnnotation
public class Student {
@TestAnnotation
private String name;
@TestAnnotation
public static void out(){
System.out.println("我是一个学生");
}
}
注解可以用在很多地方,具体的使用范围我们可以在后面的元注解中看到。
元注解
什么是元注解呢?作用于注解上的注解,就是可以用来修饰普通的注解。
@Retention
@Rentention修饰注解的时候,它可以决定注解的存活时间,它的取值为以下三种
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
- RetentionPolicy.SOURCE,注解只在源码阶段保留,编译后注解将会被丢弃
- RetentionPolicy.CLASS,注解会在源码阶段和字节码阶段(CLASS文件)被保留,但不会加载到JVM中
- RetentionPolicy.RUNTIME,注解在任何阶段都会被保留。
@Target
@Target可以指定注解的使用范围,当注解未指定Target值时,注解可以用于任何元素之上
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
- ElementType.TYPE,作用于类,接口(包括注解),枚举
- ElementType.FIELD,作用于属性
- ElementType.METHOD,作用于方法
- ElementType.PARAMETER,作用于方法的参数
- ElementType.CONSTRUCTOR,作用于构造方法
- ElementType.LOCAL_VARIABLE,作用于局部变量
- ElementType.ANNOTATION_TYPE,作用于注解
- ElementType.PACKAGE,作用于包
- ElementType.TYPE_PARAMETER,作用于类型参数声明
- ElementType.TYPE_USE,作用于类型使用声明
@Inherited
Inherited翻译过来是继承的意思,这个注解的意思是一个注解如果被@Inherited所注解,那么这个注解修饰的类的子类如果没有被其他注解所修饰,将会默认继承这个注解
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}
package org.zj;
import java.lang.annotation.*;
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface TestAnnotation {
}
package org.zj;
@TestAnnotation
public class Dad {
}
package org.zj;
public class Son extends Dad{
}
package org.zj;
import java.lang.annotation.Annotation;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
Dad dad = new Dad();
Annotation[] dadAnnotations = dad.getClass().getAnnotations();
System.out.println("dad的注解为"+ Arrays.toString(dadAnnotations));
Son son = new Son();
Annotation[] sonAnnotations = son.getClass().getAnnotations();
System.out.println("son的注解为"+Arrays.toString(sonAnnotations));
}
}
输出结果:
dad的注解为[@org.zj.TestAnnotation()]
son的注解为[@org.zj.TestAnnotation()]
@Repeatable
可重复的,被@Repeatable修饰的注解可以重复使用,如果没有@Repeatable,我们以前一般是这样来实现的,假设一个人有多重身份,我们可以在注解中定义一个数组
package org.zj;
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)
public @interface Role {
String[] value();
}
package org.zj;
@Role({"医生","儿子","父亲"})
public class Person {
}
当有了@Repetable我们可以用以下方式实现
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Roles {
Role[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(Roles.class)
public @interface Role {
String value();
}
@Role("医生")
@Role("儿子")
@Role("父亲")
public class Person {
}
在这里Roles相当于一个容器注解,我们将使用Roles注解作为接收同一个类型上重复注解的容器
注解支持的数据类型
- 八大基本数据类型
- String
- Class
- enum
- Annotation
- 以上类型数组
public @interface LogAnnotation {
//注解的属性默认值不能为Null
//定义一个枚举
enum TestEnum{SUCCESS,FAIL}
int value();
String name();
//枚举类型
TestEnum status() default TestEnum.SUCCESS;
//Class类型
Class<?> testClass();
//注解嵌套
TestAnnotation testAnnotation() default @TestAnnotation;
//数组
String[] stringArray();
}
Java内置注解
- @Override,用于标识子类的方法重写了父类的方法
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
- @Deprecated,用于表示已经过时的方法或类,被其修饰的方法或类我们调用时会有一个横线
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
- @SuppressWarnings,阻止编译器警告
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
deprecation:使用了不赞成使用的类或方法时的警告;
unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型;
fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
path:在类路径、源文件路径等中有不存在的路径时的警告;
serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
finally:任何 finally 子句不能正常完成时的警告;
all:关于以上所有情况的警告。
如何在开发中使用注解
相信看到这里的读者们都应该对注解有一个简单的了解,也会简单的定义一个注解,可是光定义一个注解好像也没啥用,甚至不如注释呢,要想使用注解,离不开一个必要的手段就是反射。
注解的常用方法
返回值 | 方法名称 | 说明 |
---|---|---|
getAnnotation(Class annotationClass) | 如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。 | |
Annotation[] | getAnnotations() | 返回此元素上存在的所有注解。 |
Annotation[] | getDeclaredAnnotations() | 返回直接存在于此元素上的所有注解。 |
boolean | isAnnotation() | 如果此 Class 对象表示一个注解类型则返回 true。 |
boolean | isAnnotationPresent(Class<? extends Annotation> annotationClass) | 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。 |
package org.zjj;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface TestAnnotation {
}
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)
public @interface AnnotationB {
}
package org.zjj;
@TestAnnotation
public class Fu {
}
import java.lang.annotation.Annotation;
import java.util.Arrays;
@AnnotationB
public class Zi extends Fu{
public static void main(String[] args) {
//返回此元素上存在的所有注解
Zi zi = new Zi();
Annotation[] annotations = zi.getClass().getAnnotations();
System.out.println("此元素上存在的所有注解"+Arrays.toString(annotations));
//获取直接存在此元素上的注解
Annotation[] declaredAnnotations = zi.getClass().getDeclaredAnnotations();
System.out.println("此元素直接存在的所有注解"+Arrays.toString(declaredAnnotations));
//返回指定的注解,如果不存在,在返回Null
AnnotationB annotation = zi.getClass().getAnnotation(AnnotationB.class);
System.out.println("获取此类上的指定注解"+annotation);
//判断此对象是否为一个注解对象
boolean annotation1 = zi.getClass().isAnnotation();
System.out.println("判断此对象是否为一个注解对象"+annotation1);
//判断指定的注解是否存在此元素上
boolean annotationPresent = zi.getClass().isAnnotationPresent(AnnotationB.class);
System.out.println("判断指定的注解是否存在此元素上"+annotationPresent);
}
}
此元素上存在的所有注解[@org.zjj.TestAnnotation(), @org.zjj.AnnotationB()]
此元素直接存在的所有注解[@org.zjj.AnnotationB()]
获取此类上的指定注解@org.zjj.AnnotationB()
判断此对象是否为一个注解对象false
判断指定的注解是否存在此元素上true