一、概要
注解对于开发人员来讲既熟悉又陌生,熟悉是因为只要你是做开发,
Java注解又称为标注,是Java从1.5开始支持加入源码的特殊语法元数据;对修饰的元素进行解释说明
二、应用场景
- 动态配置信息
- 配合反射实现程序逻辑
- 代码格式检查,比如Override、Deprecated、NonNull等,便于IDE能够检查出代码错误
三 常见内置注解(了解)
1、@Override
标记注解,不需要设置属性值;只能添加在方法的前面,用于标记该方法是复写的父类中的某个方法,如果在父类没有的方法前面加上@Override注解,编译器会报错:
2、 @Deprecated
标记注解,不需要设置属性值;作用是标记当前的类或者方法或者字段等已经不再被推荐使用了,可能在未来的版本中会删除
3、@SuppressWarnings
可以对构造方法、变量、方法、包、参数标记,用于告知编译器忽略指定的警告,不用再编译完成后出现警告信息
4、 @Nullable
用于标记方法参数或者返回值可以为空;
5、@NonNull
用于标记方法参数或者返回值不能为空,如果为空编译器会报警告;
四、自定义注解(重点)
1、说明
注解跟 classs, interface,enum一样,注解也属于一种类型。
2 、语法格式
-
格式
public @interface 注解名 {定义体}
-
说明
他定义的形式跟接口很类似,不过前面多了一个 @ 符号。
-
举个栗子
public @interface TestAnnotation { }
3 、注解的应用
-
说明
注解可以用在类,接口 枚举等任何地方
-
举个栗子
@TestAnnotation public class User { @TestAnnotation private String name; @TestAnnotation public void setName(@TestAnnotation name){ } } @TestAnnotation public enum Color { } @TestAnnotation public interface TestService { }
4、注解的属性
-
说明
注解的属性也叫做成员变量。注解只有成员变量,没有方法。
注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
-
语法格式
public @interface TestAnnotation { 类型 变量() default 默认值; }
-
类型可选值
-
基本类型(int,float,boolean,byte,double,char,long,short)
-
String类型
-
Class类型
-
enum类型
-
Annotation类型
-
以上所有类型的数组
-
-
例如
public @interface TestAnnotationField { String value() int id() default "0"; String hello() default ""; Stirng[] detail(); } /* * 1. 只能用public或默认(default)这两个访问权修饰.例如,String value() * 2. 可以设置defaul值 如果设置了default值,在使用的时候可以省略不写 */
-
使用
// 赋值的方式是在注解的括号内以 value="" 形式,多个属性之前用 ,隔开。 @TestAnnotationField(value='test', id=1, hello="坤坤", detail=['1','2','3']) public class User { }
-
注意如果属性的名称是value时可以省略
public @interface TestAnnoValue { String value() } @TestAnnoValue("value可以省不写") public class User { }
五、元注解
用于修饰注解的注解叫元注解,内置的元注解
@Retention、@Documented、@Target、@Inherited、@Repeatable(jdk1.8新增)5 种。
1、@Retention(重点)
- 作用
表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
-
语法格式
public @interface Retention { RetentionPolicy value(); }
-
可选值
可选值 说明 RetentionPolicy.SOURCE 在源文件中有效(即源文件保留) RetentionPolicy.CLASS 在class文件中有效(即class保留) RetentionPolicy.RUNTIME 在运行时有效(即运行时保留) -
举个栗子
@Retention(RetentionPolicy.SOURCE) public @interface RetentionDemo { }
2、@Target(重点)
-
作用
Target 是目标的意思,@Target 指定了注解可以修饰那些元素,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。
-
语法格式
public @interface Target { ElementType[] value(); }
-
可选值
类型 说明 ElementType.ANNOTATION_TYPE 可以给一个注解进行注解 ElementType.CONSTRUCTOR 可以给构造方法进行注解 ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举 ElementType.FIELD 可以给属性进行注解 ElementType.LOCAL_VARIABLE 可以给局部变量进行注解 ElementType.METHOD 可以给方法进行注解 ElementType.PACKAGE 可以给一个包进行注解 ElementType.PARAMETER 可以给一个方法内的参数进行注解 ElementType.TYPE_USE 可以用于标注任意类型
3、@Inherited(掌握)
-
作用
使用此注解声明出来的自定义注解,在使用此自定义注解时,
-
注意事项
如果注解在类上面时,子类会自动继承此注解,否则的话,子类不会继承此注解。也就是说使用Inherited声明出来的注解,只有在类上使用时才会有效,对方法,属性等其他无效
-
语法格式
public @interface Inherited { }
-
举个栗子
/** * 没有使用Inherited元注解,表示此注解用在类上时,不会被子类所继承 * @author zhangwei */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) public @interface NoInheritedAnnotation { String value(); } @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface InheritedAnnotation {
String value();
}
```java
@InheritedAnnotation("使用Inherited的注解class")
@NoInheritedAnnotation("未使用Inherited的注解class")
public class Parent {
@InheritedAnnotation("使用Inherited的注解 field")
@NoInheritedAnnotation("未使用Inherited的注解field")
public String name;
@InheritedAnnotation("使用Inherited的注解 method")
@NoInheritedAnnotation("未使用Inherited的注解 method")
public String getName() {
return name;
}
}
4、@Repeatable
-
作用
java8 新增的,允许在同一修饰的类型(类,属性,或方法)的多次使用同一个注解
-
举个栗子
// jdk8 之前 @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Annotation8 { String [] value(); } //使用 @Annotation8({"/update","/add"}) public class TestAnno{ }
/* * 1. 定义需要重复的注解 * 3.在需要重复使用的注解上的值指向容器的.class */ @Repeatable(RepeatableContainer.class) public @interface RepeatableAnnotation { String value(); } /* * 2.定义个一容器注解 */ public @interface RepeatableContainer { RepeatableAnnotation[] value(); } // 测试 public class RepeatTest { @RepeatableAnnotation("1") @RepeatableAnnotation("2") public void toDo() { } }
5、@Documented(了解)
-
作用
用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。
七、注解与反射
1、说明
在以下的类中Class Constructor Field Method Package等类都实现了AnnotatedElement接口相关API
同时配合反射提供的api我们就可以在程序运行时(@Retention(RetentionPolicy.RUNTIME))拿到注解
2、注解相关api
方法 | 说明 |
---|---|
getDeclaredAnnotations() | 获取声明过的所有Annotation |
getAnnotations() | 获取所有的Annotation |
isAnnotationPresent(Class<? extends Annotation> annotationClass) | 判断annotation是否存在 |
getAnnotations(Class annotationType) | 获取一个指定的annotation类型 |
3、举个栗子
-
综合栗子
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface FieldAnnotation { String name(); int id() default 0; }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface MethodAnnotation { String value(); }
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE_USE) public @interface TypeAnnotation { String value(); int id() default 0; }
@TypeAnnotation(value = "注解在类上使用", id = 1) public class TestBean { @FieldAnnotation(name = "注解在变量上使用") private String name; @MethodAnnotation(value = "在方法上使用") public String getName() { return name; } public void setName(String name) { this.name = name; } }
-
注解继承
@Inherited @Target(ElementType.TYPE_USE) @Retention(RetentionPolicy.RUNTIME) public @interface ParentAnnotation { String id(); }
4、封装ORM
-
属性
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.FIELD,ElementType.METHOD}) public @interface TableField { public String name(); public boolean isPrimaryKey() default false; }
-
表
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface Table { String tableName(); }