注解
注解概述
从
JDK5
开始,Java 增加对元数据
的支持,也就是注解,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记,可以在编译,类加载,运行
时被读取,并执行相应的处理。通过注解开发人员可以在不改变原有代码和逻辑的情况下在源代码中嵌入补充信息。应用于包、类型、构造方法、方法、成员变量、参数及本地变量
的声明语句中。本质上是一个继承了
Annotation
的特殊接口。
元注解
注解之上的注解,用来定义注解。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
元注解有六种:
@Target
:什么地方使用该注解- ElementType.CONSTRUCTOR:用于描述构造器
- ElementType.FIELD:成员变量、对象、属性(包括enum实例)
- ElementType.LOCAL_VARIABLE:用于描述局部变量
- ElementType.METHOD:用于描述方法
- ElementType.PACKAGE:用于描述包
- ElementType.PARAMETER:用于描述参数
- ElementType.TYPE:用于描述类、接口(包括注解类型) 或enum声明
@Retention
: 什么时候使用该注解- RetentionPolicy.SOURCE:在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
- RetentionPolicy.CLASS:在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。
- RetentionPolicy.RUNTIME :始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。
@Documented
:注解是否将包含在JavaDoc中@Inherited
:是否允许子类继承该注解@Repeatable
:1.8 新增,允许一个注解在一个元素上使用多次@Native
:1.8新增,修饰成员变量,表示这个变量可以被本地代码引用,常常被代码生成工具使用
JDK内置注解
@Override
:方法重写@Deprecated
:表示方法已经过时,方法上有横线,使用时会有警告。@SuppressWarnings
:表示关闭一些警告信息(通知java编译器忽略特定的编译警告)@SafeVarargs
: (jdk1.7更新) 表示:专门为抑制“堆污染”警告提供的。@FunctionalInterface
:(jdk1.8更新) 表示:用来指定某个接口必须是函数式接口,只能有一个需要实现的抽象方法,否则就会编译出错。
自定义注解
自定义注解规则
- 自定义注解需要添加元注解
- 所有 Annotation 定义类型为
@interface
,会自动继承java.lang.Annotaion
这个接口,并且不能再去继承别的类或是接口。 - 参数成员只能用 public 或默认(default) 这两个访问权修饰。
- 参数成员只能是
byte、short、char、int、long、float、double、boolean
八种基本数据类型和String、Enum、Class、annotations
等数据类型,以及这一些类型的数组. - 要获取类方法和字段的注解信息,必须通过 Java 的
反射
技术来获取 Annotation 对象,因为除此之外没有别的获取注解对象的方法 - 注解也可以没有定义成员,不过这样注解就没啥用了
创建自定义注解
需求:
创建一个注解,用于添加在字段上,可以起到给字段赋值的作用
步骤:
-
创建注解
import java.lang.annotation.*; // 作用于字段 @Target(ElementType.FIELD) // 运行期间有效 @Retention(RetentionPolicy.RUNTIME) public @interface AnnotationDemo { // 类型 属性名 默认属性值 String value() default "龙傲天"; }
-
创建实体类
public class User { @AnnotationDemo("李四") private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "User{" + "name='" + name + '\'' + '}'; } }
-
利用反射注解解析并赋值
import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Test { public static Object getObject(String className) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException { Class<?> clazz = Class.forName(className); Object obj = clazz.newInstance(); Field[] declaredFields = clazz.getDeclaredFields(); // 遍历所有字段 for (Field field : declaredFields) { // 判断字段上是否添加有此注解 if (field.isAnnotationPresent(AnnotationDemo.class)){ // 获得该字段上存在的该注解对象 AnnotationDemo annotation = field.getAnnotation(AnnotationDemo.class); // 获得字段的名称 String fieldName = field.getName(); // 得到修改该字段的方法 Method setMethod = clazz.getDeclaredMethod("set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1), String.class); // 调用该方法,传入注解的值 setMethod.invoke(obj,annotation.value()); } } return obj; } }
-
测试
import java.lang.reflect.InvocationTargetException; public class Method { public static void main(String[] args) throws ClassNotFoundException, InvocationTargetException, NoSuchMethodException, IllegalAccessException, InstantiationException { User user = (User) Test.getObject("com.dong.User"); System.out.println(user); } }
-
输出
User{name='李四'}