Java注解的使用【奔跑吧!JAVA】
【摘要】 一、简介注解是一种特殊的接口,注解继承自 java.lang.annotation.Annotation1.所有注解类型都会继承 Annotation 接口2.手工显示继承 Annotation 接口,不会定义成一个注解类型3.Annotation 本身并不会定义成一个注解类型二、分类注解可以分为 元注解、内置注解、用户自定义注解2.1 元注解一种基本注解,可以应用在其它的注解上。可以这样理...
一、简介
注解是一种特殊的接口,注解继承自 java.lang.annotation.Annotation
1.所有注解类型都会继承 Annotation 接口
2.手工显示继承 Annotation 接口,不会定义成一个注解类型
3.Annotation 本身并不会定义成一个注解类型
二、分类
注解可以分为 元注解、内置注解、用户自定义注解
2.1 元注解
一种基本注解,可以应用在其它的注解上。可以这样理解,元注解是用于标记注解的注解
元注解有:
- java.lang.annotation.Retention
- java.lang.annotation.Target
- java.lang.annotation.Documented
- java.lang.annotation.Inherited
- java.lang.annotation.Repeatable
- java.lang.annotation.Native
通过@符号加注解名称连起来使用,如@Retention,@Target等
@Retention
@Retention 是保留的意思,用于设置注解的生命周期。其值是 java.lang.RetentionPolicy
枚举类。
- RetentionPolicy.SOURCE : 只在源代码级别保留有用,在编译时就丢弃了
- RetentionPolicy.CLASS : 在编译时保留有效,在运行时(JVM中)开始丢弃;这是默认的生命周期
- RetentionPolicy.RUNTIME : 在编译时、运行时都保留有效,所以可以在反射中使用
生命周期长度是 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在运行时去动态获取注解信息,那只能用 RUNTIME 注解;如果要在编译时进行一些预处理操作,比如生成一些辅助代码,就用 CLASS注解;如果只是做一些检查性的操作,比如 @Override 和 @SuppressWarnings,则可选用 SOURCE 注解。
使用如下,自定义的注解上添加注解产生的时间限制:
@Retention(RetentionPolicy.RUNTIME)
public @interface Test(){
... ...
}
@Target
@Target 以数组形式标明注解使用的约束应用上下文,用来表示注解作用范围,超过这个作用范围,编译的时候就会报错,并且可以标记在多个范围中,值由 java.lang.annotation.ElementType
指定。
java.lang.annotation.ElementType 的可用值如下:
- TYPE : 类、接口、注解、枚举的声明中
- FIELD : 成员变量,包含枚举的常量的声明中
- METHOD : 方法的声明中
- PARAMETER : 正式的参数的声明中
- CONSTRUCTOR : 构造器的声明中
- LOCAL_VARIABLE : 局部变量的声明中
- ANNOTATION_TYPE : 注解类型的声明中
- PACKAGE : 包的声明中
- TYPE_PARAMETER : 类型参数的声明中(since JDK8)
- TYPE_USE : 类型的使用(since JDK8)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface Test(){
... ...
}
@Documented
@Documented 表明注解的类型将会包含到Javadoc中去,只是用来标识。
@Documented
public @interface Test(){
... ...
}
@Inherited
@Inherited 继承的意思,如果标记了该注解的注解,在子项没有其他注解标注时,子项会自动继承父项的该注解
注:子类继承了父类(由于继承特性,子类会拥有父类的公有一切),在通过反射获取子类所有公有字段/方法/构造器的时候,会获取得到自身和父亲的所有public字段/方法/构造器,而通过反射获取所有任何字段/方法/构造器的时候,只能得到自身的所有任何访问权限修饰符的字段/方法/构造器,不会得到父类的任何字段/方法/构造器。然注解不一样,只有当父类的注解中用@Inherited修饰,子类的getAnnotations()才能获取得到父亲的注解以及自身的注解,而getDeclaredAnnotations()只会获取自身的注解,无论如何都不会获取父亲的注解。
@Inherited
public @interface Marks(){}
//父项
@Marks
public class superTest(){}
//子项
public class childTest extends superTest(){}
//此时相当于
@Marks
public class childTest extends superTest(){}
@Repeatable
@Repeatable是jdk8中新增的注解,在没有@Repeatable注解的的注解中,在同一个地方使用相同的注解会报错,有了此元注解注解的注解,就可以在同一个地方使用相同的注解
//先创建个基础注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface BaceTest(){
String value() default "value";
}
//开始创建数组形式的注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {
BaceTest[] value();
}
//使用
@Test("今天天气真好")
@Test("晚上去撸串吧")
public string test(){
... ...
}
2.2 Java内置注解
-
@FunctionalInterface : 函数式接口:一个具有一个方法的普通接口。
-
@Override : 实现类要重写父类或者接口的方法
-
@SafeVarargs : 参数安全类型注解,告诉开发者不要用参数做一些不安全的操作
-
@SuppressWarnings : 阻止编译器发出告警,比如调用了使用了 @Deprecated 标记的方法编译器会发出警告,可以使用 @SuppressWarnings 压制警告
-
- all : @SuppressWarnings("all") ,会阻止所有的警告
- cast : 阻止类造型转换警告
- deprecation : 阻止废弃的警告,比如可能使用了 @Deprecated
- divzero : 阻止除数为0的警告
- unchecked : 阻止没有指定泛型的集合表达式
- fallthrough : 阻止 switch警告,比如某个case没有break语句
- serial : 阻止实现 Serializable 接口但是没有声明 serialVersionUID 属性的警告
- finally :阻止没有正确使用finally的警告,比如没有捕获异常,编译器会发出警告
- @Deprecated : 表示废弃,在编译时会发出警告
2.3 注解与反射结合使用
- 可以通过 java.lang.reflect.Class 的 isAnnotationPresent() 得知是否存在注解。
- 可以通过 <T extends Annotation> T getAnnotation(Class<T> annotationClass) 方法获取注解对象
- 可以通过 Annotation[] getAnnotations() 方法获取注解列表
- 可以通过Class类的对象包含了某个被加载类的结构。一个被加载的类对应一个 Class对象。
- 当一个class被加载,或当加载器(class loader)的defineClass()被 JVM调用,JVM 便自动产生一个Class 对象
反射是一个动态的机制,允许我们通过字符串来指挥程序实例化,操作属性、调用方法。使得代码提高了灵活性,但是同时也带来了更多的资源开销。加载完类之后,在堆内存中,就产生了一个 Class 类型的对象(一个 类只有一个 Class 对象),这个对象就包含了完整的类的结构信息。 我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过 这个镜子看到类的结构,所以,我们形象的称之为:反射。
如果我们需要获取类上的注解,只需要获取到类对象,然后.getDeclaredAnnotation()即可。
@Test
public void testValue() {
Method[] methods = Test.class.getMethods();
for (Method method : methods){
if (method.getName().equals("testName")) {
Annotation[] annotations = method.getDeclaredAnnotations();
System.out.println(annotations.length);
System.out.println(method.getName() + " = " + Arrays.toString(annotations));
}
}
}
2.4 补充知识点
1.注解只有变量(属性),没有方法, 注解的属性是以无参方法的形式声明的。
2.属性后面使用 default
关键字可以给属性设置默认值
public @interface Test {
//属性
String name() default '张小明';
}
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)