`

Java注解知识点总结

 
阅读更多
Java的注解(Annotation)是Java5以后引入的,又叫元数据,也有人翻译成注释,用作给代码元素做标记,可以携带一些说明或配置信息,但是注解本身并不参与代码的运行,需要时必须对编写代码提取注解信息。注解可以修饰的一个类里面的各个组成元素,比如可以修饰类和接口的声明、构造方法、字段、方法还有方法参数等等,具体可以修饰什么元素得看该注解的声明。
注解主要有三个知识点:
一. Java提供的注解
二. 利用元注解自定义注解
三. 提取注解信息

注解使用的语法形式是
@AnnotationName


@AnnotationName(valueName1 = value1, valueName2 = value2, …)

当valueName只有一个并且就是“value”,
我们可以省略valueName,写成如下形式:
@AnnotationName(value)

如不省略则如下
@AnnotationName(valueName = value)

注解的用法与Java修饰符一样,一般写在修饰符的最前面,并且独占一行,因注解可能存在参数,所以我们惯常的写法如下(以声明一个类为例),当然不换行语法上也是正确的。
@ AnnotationName
Public class ClassName{
	// …
}

一.Java提供的注解
下面介绍Java提供的五个常用的注解:
1. 用于标记Java代码元素已过时的注解:@Deprecated
用 @Deprecated 注解的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择,这种程序元素很可能下一代API就取消掉了。在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告。@Deprecated注解基本可以用于任何程序元素。
2. 用于标记重写基类方法的注解:@Override
表示一个方法声明打算重写基类中的另一个方法声明。如果方法利用此注解类型进行注解但没有重写基类方法,则编译器会生成一条错误消息。@Override注解只能用于方法生命时。
3. 用于标记抑制编译器警告的注解:@SuppressWarnings
用 @ SuppressWarnings注解的程序元素可能会产生编译器警告,而使用了这个注解则表示取消了编译器的警告信息。@SuppressWarnings注解基本可以用于任何程序元素。
4. 用于标记方法编译时可能发生堆污染警告的注解(Java7新增注解):@SafeVarargs
在将非泛型对象赋值给泛型对象时会产生泛型擦除,而在赋值后的非泛型对象上取值操作时会产生运行时异常,称之为堆污染(Heap Pollution)。使用@SafeVarargs注解修饰后,将不会产生堆污染警告。@SafeVarargs只能用在构造方法或普通方法声明时。事实上在使用Eclipse编写Java代码时对@SafeVarargs注解修饰的方法会报错,一般会使用@SuppressWarnings("unchecked")替代。
5. 用于标记函数式接口的注解(Java8新增):@FunctionalInterface
Java8新增了函数式编程,只含有一个抽象方法的接口在Java8中称为函数式接口,使用@FunctionalInterface注解修饰。@FunctionalInterface注解只能用在接口声明时。
使用示例如下:
@FunctionalInterface
interface MyFunctionalInterface{
	void method(List<String> ... lists );
}
@Deprecated
public class AnnotationTest implements MyFunctionalInterface{
	@SuppressWarnings({ "unused"})
	private String field;
	@Override
	@SafeVarargs	// @SafeVarargs在Eclipse编辑器中不支持,直接代码提示方法签名报错
	public void method(List<String> ... lists ) {
		// ...
	}
	public static void main(String[] args) {
		List<String> localField1 = new ArrayList<String>();
		List<String> localField2 = new ArrayList<String>();
		// 这一行会引发堆污染
		new AnnotationTest().method(localField1, localField2);
	}
}

二.利用元注解自定义注解
Java提供了几个用来定义注解的注解,又叫元注解,只能用在类型声明上,用来定义注解的使用范围和生命周期等等。
@Documented 用于标记一个注解是否会被javadoc提取成API文档
@Inherited 用于标记一个注解是否会被使用的类的扩展类继承,该注解修饰的注解只能用在类的声明上才有效,
@Retention 用于标记一个注解的声明周期,使用枚举类RetentionPolicy的三个枚举值决定,只能使用其中一个枚举值。
SOURCE 编译器要丢弃的注解。
CLASS 编译器将把注解记录在类文件中,但在运行时 VM 不需要保留注解。
RUNTIME 编译器将把注解记录在类文件中,在运行时 VM 将保留注解,因此可以反射性地读取。
@ Target 用于标记一个注解能够用于哪些程序元素,使用枚举类ElementType的枚举值决定,可以使用多个枚举值。
ANNOTATION_TYPE 注解类型声明
CONSTRUCTOR  构造方法声明
FIELD  字段声明(包括枚举常量)
LOCAL_VARIABLE  局部变量声明
METHOD 方法声明
PACKAGE 包声明
PARAMETER 参数声明
TYPE 类、接口(包括注解类型)或枚举声明
Java8又新增了两个枚举值
TYPE_PARAMETER Type parameter declaration(类型参数声明)
TYPE_USE Use of a type(一个类的任意元素都可使用)
Java8新增了两个元注解
@ Repeatable 用于标记一个注解可以重复多次使用在一个程序元素上。
@ Native 用于标记一个注解用在一个字段的常量值可能来自非Java代码,这是目前Java元注解中唯一一个RetentionPolicy. SOURCE级别的元注解,其余元注解都是RUNTIME级别的。平时似乎也不会用到。

Java定义注解的语法使用@interface来定义,例如我们可以定义一个这样的注解。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@interface MyAnnotation{
	String value();
}

现在这个注解只能使用在字段和普通方法上,如
// @MyAnnotation("该注解声明Target时没用使用TYPE枚举值,不能使用在类和接口等的声明上")
public class AnnotationUserDefined {
	@MyAnnotation("默认的value数据赋值可以省略value = ")
	public String field;
	@MyAnnotation(value = "不省略value = 得写法")
	public void method(){
		// ...
	}
}

从上面的用法上可以看到,注解内声明字段的语法不再是普通字段声明的语法,而是和普通方法的声明一样。上面声明了一个value的字段,当注解声明的字段只有一个value时,注解使用时赋值操作可以省略“value = ”,当注解声明的字段名不叫value时或有多个字段(即使其中一个字段包含value),赋值操作不能省略字段名。
如字段名不叫value
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@interface MyAnnotation{
	String name();
}

使用时必须这样
@MyAnnotation(name = "不能省略name = ")

如不是只有一个value字段时
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@interface MyAnnotation{
	String value();
	String name();
}

使用时必须这样
@MyAnnotation(value = "不能省略value= ", name = "不能省略name = ")

若是在@MyAnnotation注解的声明上使用@Inherited修饰,则使用@MyAnnotation注解修饰的类的扩展类若没有使用该注解修饰,也自动继承了@MyAnnotation注解。同时,在@MyAnnotation声明上,@Target必须加上ElementType.TYPE枚举值或ElementType.TYPE_USE,否则该注解不起作用。
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@interface MyAnnotation{
	String value();
}

那么@MyAnnotation就可以使用在类型声明上了。
@MyAnnotation("在类型声明上使用该注解")
public class AnnotationUserDefined {
	@MyAnnotation("默认的value数据赋值可以省略value = ")
	public String field;
	@MyAnnotation(value = "不省略value = 得写法")
	public void method(){
		// ...
	}
}
// 此处自动继承了基类AnnotationUserDefined的@MyAnnotation,反射可以获取注解信息
class AnnotationUserDefinedExt extends AnnotationUserDefined{
}

在Java8之前,没有@ Repeatable注解时,要使用类似重复注解的功能必须要一个注解容器,这个容器也是注解类型的,还是上面那个@MyAnnotation为例,必须有一个@MyAnnotations这样的注解容器
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD})
@interface MyAnnotations{
	MyAnnotation[] value();
}

而@MyAnnotation的声明则如下
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@interface MyAnnotation{
	String value();
}

我们使用重复注解效果时,则如下
@MyAnnotations({
		@MyAnnotation("默认的value数据赋值可以省略value = "),
				@MyAnnotation(value = "不省略value = 得写法")})

在Java8引入重复注解功能以后,@MyAnnotations注解容器的声明不变,我们只需要在@MyAnnotation注解的声明上加一行@Repeatable(MyAnnotations.class)就行了,如下
@Repeatable(MyAnnotations.class)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.TYPE})
@interface MyAnnotation{
	String value();
}

而我们在使用重复注解功能时,则如下
@MyAnnotation("默认的value数据赋值可以省略value = ")
@MyAnnotation(value = "不省略value = 得写法")

重复两个注解修饰同一个程序元素,就不需要吧注解容器写出来了。
使用@Repeatable注解容器声明时修饰的元注解必须与该注解一样,@Target的枚举值不能只能少于该注解的范围,并且不能含有该注解没有的枚举值。如@MyAnnotations这个注解容器则不能使用ElementType.PARAMETER这个枚举值。

四. 提取注解信息
提取注解信息是使用反射来实现的,反射只能获取@Retention(RetentionPolicy.RUNTIME)修饰的注解的信息,若是SOURCE和CLASS级别的注解,反射是获取不到的,只能使用代码分析框架和字节码分析框架是获取注解信息了。
Java的反射知识点参考我的博文Java反射知识点总结
Java的每种类型的程序元素(Class、Constructor、Field、Method、Parameter)都实现了AnnotatedElement接口,当反射获取到一个程序元素后,就可以使用以下方法获得该程序元素上修饰的注解和注解上的字段信息。
<T extends Annotation> T getAnnotation(Class<T> annotationClass)
如果存在该元素的指定类型的注解,则返回这些注解,否则返回 null。
Annotation[] getAnnotations()
返回此元素上存在的所有注解。
Annotation[] getDeclaredAnnotations()
返回直接存在于此元素上的所有注解。
Boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
如果指定类型的注解存在于此元素上,则返回 true,否则返回 false。
Java8新增的获取注解的方法如下:
<T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass)
如果存在直接存在于该元素的指定类型的注解,则返回这些注解,否则返回 null。
<T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass)
由于Java8引入了重复注解,如果存在该元素的指定类型的注解,该方法则返回这些注解,否则返回 null。
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
由于Java8引入了重复注解,如果存在直接存在于该元素的指定类型的注解,该方法则返回这些注解,否则返回 null。
还是刚刚的@MyAnnotation注解为例,我们使用反射获取该注解。
public static void main(String[] args) {
		MyAnnotation anno = AnnotationUserDefined.class.getAnnotation(MyAnnotation.class);
		MyAnnotation anno = AnnotationUserDefined.class.getAnnotation(MyAnnotation.class);
		System.out.println(anno);	
		System.out.println(((Annotation) anno).annotationType());
		System.out.println("该注解的value值:" + anno.value());	}

代码执行结果如下



AnnotatedElement接口的子接口AnnotatedType接口,还有AnnotatedType接口的四个子接口AnnotatedArrayType、AnnotatedParameterizedType、AnnotatedTypeVariable和AnnotatedWildcardType从名字上看跟Type接口及其四个子接口一一对应,似乎与泛型有关。文档中也没有有用的说明。
System.out.println(AnnotationUserDefined.class.getAnnotatedSuperclass());

这一行代码将会打印出类似以下信息
sun.reflect.annotation.AnnotatedTypeFactory$AnnotatedTypeBaseImpl@6d06d69c

sun开头的包名,说明AnnotatedTypeFactory是没有公开的API,反编译AnnotatedTypeFactory这个类,找到了分别找到了AnnotatedType接口的四个子接口AnnotatedArrayType、AnnotatedParameterizedType、AnnotatedTypeVariable和AnnotatedWildcardType的实现类。然后并没有找到什么有用的信息。。。
注解上目前也是不支持泛型的使用。

更详细的注解知识点参考http://ifeve.com/java-annotations-tutorial/
  • 大小: 5.7 KB
1
1
分享到:
评论

相关推荐

    java重要知识点总结

    1.java是一种编译解释型的语言。 2.java的垃圾回收机制: java的垃圾回收将在程序运行过程中自动进行,无需程序员负责...6.java注释: // 单行注释 /* */ 多行注释(不能嵌套) //* */ 文档说明注释 ...... .... .....

    java代码知识点总结

    JAVA知识点汇总 必须养成优秀程序员的编写习惯:缩进(用空格)、注释、命名约定。 大小写敏感。 单独的“;”代表一条空语句。 main函数是我们整个程序的执行入口所以必须是静态公开的。 必须写成这样: public ...

    Java知识点总结.zip

    动态性:Java可以通过反射、注解等机制实现在运行时动态加载类和修改行为,增加了程序的灵活性。 综上所述,Java凭借其强大的特性和广泛的适用范围,在企业级应用、互联网服务、移动开发等领域均扮演着举足轻重的...

    javaOOP文档、知识点总结.CHM

    本文档总结javaOOP所有关键知识,包括java基础知识、面向对象、常用API、多线程、集合、IO、泛型、枚举、反射、注解等概念性知识。

    java基础的注解和反射的相关知识点总结

    ,注解与注释是有一定区别的,可以把注解理解为代码里的特殊标记 反射和反射机制 反射(Reflection): Java的反射是指程序在运行期可以拿到一个对象的所有信息。 反射的优点和缺点: 优点:可以实现动态创建对象...

    Java 排序算法知识点总结.zip

    动态性:Java可以通过反射、注解等机制实现在运行时动态加载类和修改行为,增加了程序的灵活性。 综上所述,Java凭借其强大的特性和广泛的适用范围,在企业级应用、互联网服务、移动开发等领域均扮演着举足轻重的...

    Java基础知识小结

    1.10 Java集合框架使用总结 . . . . . . . . . . . . . . . . . . . . . . . 26 1.11 抽象类与接口的区别 . . . . . . . . . . . . . . . . . . . . . . . . 29 1.12 面向对象设计61点经验原则 . . . . . . . . . . ...

    mybatis知识点总结.docx

    MyBatis知识点总结 MyBatis是一款优秀的持久层框架,为Java应用程序提供了数据库访问的灵活性和高度可控性。以下是关于MyBatis的一些重要知识点总结: 1. MyBatis基础: MyBatis是一个支持自定义SQL、存储过程和...

    JAVA面向对象基础总结笔记

    这个文档是我本人通过学习JAVA面向对象部分总结出的文档,知识点都包含在内,继承,封装,多态等概念,以及相关代码并给于注释,面向对象部分是JAVA的核心部分,面向对象这部分是理解JAVA的最好途径,共大家学习借鉴...

    Java基础知识总结

    记笔记,加注释,写总结 不要完全依赖于书和视频 建立有效的学习方法 学习软件编程的捷径--敲,狂敲 写代码: 1,明确需求。我要做什么? 2,分析思路。我要怎么做? 1,2,3。 3,确定步骤。每一个思路部分用到哪些...

    注解、反射、单元测试、lombok知识点总结笔记

    关于注解、反射、单元测试、lombok等知识点的总结笔记

    MyBatis框架简单的知识点总结.zip

    MyBatis框架简单的知识点总结 MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来...

    MyBatis框架简单的知识点总结.docx

    MyBatis框架简单的知识点总结 MyBatis 是一个优秀的持久层框架,它支持定制化 SQL、存储过程以及高级映射。MyBatis 避免了几乎所有的 JDBC 代码和手动设置参数以及获取结果集。MyBatis 可以使用简单的 XML 或注解来...

    springboot知识点整理

    2.12 @Conditional派生注解 41 3 Spring Boot与日志 42 3.1 日志框架分类和选择 42 3.2 SLF4j使用 43 3.3 其他日志框架统一转换成slf4j+logback 44 3.4 Spring Boot日志使用 45 3.5 Spring Boot默认配置 47 3.6 指定...

    八股文知识点汇总——Java面试题指南

    Java注解面试题 多线程&并发面试题 JVM面试题 Mysql面试题 Redis面试题 Memcached面试题 MongoDB面试题 Spring面试题 Spring Boot面试题 Spring Cloud面试题 RabbitMQ面试题 Dubbo 面试题 MyBatis 面试题 ZooKeeper...

    Java后端面试问题整理.docx

    Java后端面试知识点总结,涉及JVM • 熟悉JVM内存区域,常用引用类型,垃圾回收机制、算法以及常见的GC垃圾收集器(Serial、ParNew、Parallel Scavenge、Serial Old、Parallel Old、CMS、G1) • 熟悉常用IO模型(BIO、...

    Java基础核心总结.pdf

    Java核心基础知识总结,含思维导图,包含Java基本语法,面向对象,接口和抽象类,异常,内部类,集合,泛型,反射,枚举,I/O,注解等Java基础核心知识,总结全面,内容丰富,欢迎下载。 如果对你有用,麻烦点个收藏...

    java技能总结.docx

    掌握Java语法和基础:掌握Java的语言特性、数据类型、运算符、控制结构、面向对象编程等基础知识点。 掌握Java标准库:掌握Java标准库中的重要类和接口,如String、ArrayList、HashMap、Thread、Socket等。 掌握Java...

    Java实训项目——嗖嗖移动大厅(详细注解)

    Java实训项目,综合面向对象、I/O、实用类、集合框架等知识点

    数据库小知识用java访问数据库

    数据库连接是软件项目开发中很重要的一个环 节,但是很多Java初学者在学习连接数据库的过程...数据库连接池连接进行归纳总结,对常见的问题给出 最佳的解决的办法,并给出了详尽的配置步骤和数据 库连接源代码和注释。

Global site tag (gtag.js) - Google Analytics