java注解
Posted 新火且试茶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java注解相关的知识,希望对你有一定的参考价值。
注解(Annotation)
Java中的注解是相当重要的知识点,在许多框架尤其是SpringBoot框架,使用注解来替代配置文件,很大程度上减少了配置的麻烦。
Java中的类,方法,变量,参数和包都可以被注解标注。然而注解本身并不具有任何逻辑功能,它的存在更像是一个标签,告诉别人应该对它标注的内容进行何种处理。
比如我们常见的注解
- @Override:检查该方法是否是重写方法
- @Deprecated:标记过时方法。
- @SuppressWarnings:指示编译器去忽略注解中声明的警告。
java中注解都实现接口Annotation
package java.lang.annotation;
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
java中注解的定义形式
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
}
要理解上面的注解形式,我们先要了解一下元注解
元注解
元注解就是可以注解到注解上的注解,是用来说明注解性质的基本注解。
@Retention
用来指定注解的保留策略,即注解的存活时间
通过枚举类RetentionPolicy的值来指定
package java.lang.annotation;
public enum RetentionPolicy {
SOURCE, /*注解只保留在源码阶段,编译器处理完之后就没有该Annotation信息了 */
CLASS, /* 编译器将Annotation存储于类对应的.class文件中,但不会加载到JVM中。默认行为 */
RUNTIME /* 编译器将Annotation存储于class文件中,可保留到程序运行时,并且可由JVM读入,因此可以通过反射读取它们 */
}
上面所提到的@Override和@SupressWarnings注解的保留策略就是SOURCE,因为只有编写源代码时我们才需要警告,在编译过后便没有必要保留。
常用的保留策略还是RUNTIME,毕竟我们通常需要在运行时对注解标注的内容进行相应的处理。
@Target
我们知道注解可以标注在类、方法、变量等,而@Target就是用来指定注解可以标注的类型。与枚举类型ElementType结合使用。
package java.lang.annotation;
public enum ElementType {
TYPE, /* 类、接口(包括注释类型)或枚举声明 */
FIELD, /* 字段声明(包括枚举常量) */
METHOD, /* 方法声明 */
PARAMETER, /* 参数声明 */
CONSTRUCTOR, /* 构造方法声明 */
LOCAL_VARIABLE, /* 局部变量声明 */
ANNOTATION_TYPE, /* 注释类型声明 */
PACKAGE, /* 包声明 */
TYPE_PARAMETER, /* 参数类型声明 1.8后新增*/
TYPE_USE /*TYPE和TYPE_PARAMETER的结合,1.8后新增 */
}
@Target可有可无,如果没有,若没有则该注解可以标注在任何地方;如果有,则该注解必须标注在指定的地方。
@Documented
类和方法的注解默认情况下是不出现在javadoc中的,使用该@Document修饰的注解,生成javadoc时会出现在javadoc中。
@Inherited
Inherited是继承的意思,如果一个类被用@Inherited标注的注解标注了的话,那么这个子类就会继承这个父类的注解。
例如有一个注解Inheritable被@Inherited标注
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface Inheritable{}
有一个父类被@Inheritable标注
@Inheritable
class InheritedFather{}
有一个继承父类的子类,这个子类没有用任何注解标注
public class InheritedSun extends InheritedFather{
public static void main(String[] args) {
//结果为true
System.out.println(InheritedSun.class.isAnnotationPresent(Inheritable.class));
}
}
上面打印结果为true,说明子类继承了父类的注解
@Repeatable
可重复的意思,java1.8后加入的,这个注解说明可以在其标注的同一个地方多次使用这个注解。
例如,您正在编写代码以使用计时器服务,以在每月的最后一天以及每个星期五的晚上11:00运行doPeriodicCleanup方法。代码如下:
声明可重复注解
import java.lang.annotation.Repeatable;
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
声明容器注解,即可存放注解的注解。容器注解必须有value属性,类型为@Repeatable注解的注解数组
public @interface Schedules {
Schedule[] value();
}
标注在doPeriodicCleanup方法上
@Schedule(dayOfMonth="last")
@Schedule(dayOfWeek="Fri", hour="23")
public void doPeriodicCleanup() { ... }
注解的属性
如上例子
@Repeatable(Schedules.class)
public @interface Schedule {
String dayOfMonth() default "first";
String dayOfWeek() default "Mon";
int hour() default 12;
}
String为类型,dayOfMonth()为属性名,default指定默认值。
使用形如@Schedule(dayOfWeek="Fri", hour="23")的格式来使用注解。
如果注解只有一个value属性,可以将value省略,直接写值,例如@Repeatable。@Repeatable(Schedules.class)
public @interface Repeatable {
Class<? extends Annotation> value();
}
,如果注解内无属性,括号也可省略。如@Override
java常用注解
- @Deprecated -- @Deprecated 所标注内容,不再被建议使用。
- @Override -- @Override 只能标注方法,表示该方法覆盖父类中的方法。
- @Documented -- @Documented 所标注内容,可以出现在javadoc中。
- @Inherited -- @Inherited只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性
- @Retention -- @Retention只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性。
- @Target -- @Target只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性。
- @SuppressWarnings -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。
- @FunctionalInterface --函数式接口注解,这个是 Java 1.8 版本引入的新特性。函数式接口 (Functional Interface) 就是一个具有一个方法的普通接口。线程开发中常用的 Runnable 就是一个典型的函数式接口,上面源码可以看到它就被 @FunctionalInterface 注解。
反射与注解
上面已经了解了注解的定义与基本知识,注解最重要的便是对其标注的内容进行处理。
下面便进行一个简单实例,使用一个注解标注在方法上,为方法内的参数赋值。
首先,自定义注释
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String[] value();
}
创建一个类
public class Person {
private String name;
private String sex;
//将注释中的值赋给方法
@MyAnnotation(value = {"张三","男"})
public void setNameAndSex(String name,String sex){
System.out.println(name + "," + sex);
}
}
测试方法
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Class<Person> clazz = Person.class;
Person person = new Person();
//通过反射获取方法
Method method = clazz.getMethod("setNameAndSex", String.class, String.class);
//如果方法被@MyAnnotation注解标注
if (method.isAnnotationPresent(MyAnnotation.class)) {
//获取这个方法的MyAnnotation注解
MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
//获取注解内的属性值
String[] value = annotation.value();
//将属性值当做参数执行方法
method.invoke(person,value[0],value[1]);
}
}
以上是关于java注解的主要内容,如果未能解决你的问题,请参考以下文章