`

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重要知识点总结

    ### Java重要知识点总结 #### 1. Java是一种编译解释型的语言 Java 语言的特点是它结合了编译型语言的高效性和解释型语言的灵活性。在开发阶段,Java 源代码首先被编译器转换成字节码(Bytecode),这是一种中间...

    java知识点总结思维导图(xmind)

    这份"java知识点总结思维导图(xmind)"是为帮助学习者系统性地理解和掌握Java核心技术而精心整理的资料。思维导图作为一种有效的学习工具,能够帮助我们更好地组织和记忆信息,提高学习效率。 首先,让我们从基础...

    Java 相关的知识点总结

    Java是一种广泛使用的面向对象的编程语言,以其跨平台、高性能和...以上就是Java相关的知识点总结,希望对你在学习和使用Java的过程中有所帮助。不断深入实践,理解和掌握这些知识点,将使你成为一名优秀的Java开发者。

    JAVA知识点总结(XMIND格式)

    以上知识点在"JAVA知识点总结思维导图(xmind)"中可能以思维导图的形式详细展开,包括每个主题的子话题和相关实例,帮助学习者系统地理解和掌握Java编程。通过深入学习和实践这些知识点,可以成为一名熟练的Java...

    java重要基础知识点总结.pdf

    本文将总结Java的重要基础知识点,帮助读者深入理解和掌握这一强大的编程工具。 1. **Java基础语法**: - 类(Class)和对象(Object)是Java的核心概念,类定义了对象的属性和行为。 - 引用数据类型包括类、接口...

    java知识点总结

    Java知识点总结 1. 前言 Java作为一种广泛使用的编程语言,因其平台无关性、安全性和稳定性而受到青睐。本资源旨在为初学者和有经验的开发者提供一个全面的Core Java知识概述,帮助大家更好地理解和掌握Java的核心...

    Java基础知识点总结

    ### Java基础知识点总结 #### 一、Day_01Java开章 1. **计算机概述** - **计算机**:一种能够自动高速处理大量信息的电子设备。 - **计算机硬件**:指计算机系统中所有看得见摸得着的物理部件,如CPU、内存、...

    《Core Java》知识点总结.doc

    这些只是《Core Java》中的一部分基础知识,书中还深入讲解了类与对象、异常处理、集合框架、IO流、网络编程、多线程、反射、注解、泛型等众多主题,对于全面掌握Java编程至关重要。对于初学者而言,理解和实践这些...

    java基础知识点总结思维导图

    ### Java基础知识点总结 #### 一、Java语言简介与环境配置 - **JDK (Java Development Kit)**: JDK 是 Java 开发工具包的基础,包含了编译器、解释器和其他工具,用于开发 Java 应用程序。 - **JRE (Java Runtime...

    java知识体系总结

    Java知识体系总结 Java是一种广泛使用的面向对象的编程语言,由Sun Microsystems(现已被Oracle公司...上述知识点只是Java庞大知识体系的一部分,深入理解并熟练运用这些概念,对于成为一名优秀的Java程序员至关重要。

    java基础知识点总结

    这份“java基础知识点总结”旨在为初学者提供一个全面而深入的学习指南,涵盖Java语言的基础概念、语法和常用API。 一、Java语言基础 1. **环境配置**:安装JDK(Java Development Kit)是开始学习Java的第一步,...

    java——知识点归纳总结

    ### Java——知识点归纳总结 #### 概述 Java是一种简单且强大的面向对象编程语言,以其跨平台特性闻名,即“一次编写,到处运行”。Java语言的设计原则包括分布性、安全性、健壮性和多线程性,使其成为互联网时代...

    java面试大全。各大公司面试总结。知识点总结,共31个文档

    Java面试大全涵盖了大量的技术知识点,这些内容通常会出现在各大公司的面试过程中。为了帮助你更好地准备,以下是基于描述中提到的“31个文档”可能涉及的一些核心Java面试知识点的详细阐述: 1. **基础概念**:...

    Java简单知识点总结

    在Java简单知识点总结中,我们将深入探讨Java的基础概念、语法特性、数据类型、控制结构、类与对象以及异常处理等方面。 1. **基础概念** - **JVM(Java虚拟机)**:Java程序通过JVM运行,它提供了跨平台的能力,...

    java 基础知识总结(经典)

    这篇“Java基础知识总结(经典)”涵盖了Java开发中的核心概念和重要知识点,旨在为初学者和有经验的开发者提供一个全面的回顾。以下是主要的学习点: 1. **Java环境配置**:在开始编程之前,必须安装Java ...

    java学习知识点总结

    Java学习知识点总结 Java语言作为一款广泛应用于企业级开发、移动应用及大数据处理的语言,其学习涵盖了许多方面。本资源包提供了从基础到高级的全面Java学习材料,包括了Java基础、前端技术、Spring框架以及多线程...

    java代码知识点总结

    以上就是Java编程基础的一些关键知识点,涵盖了编程风格、程序结构、打包发布、注释、命名约定、包管理、导入语句以及输入输出等方面的内容。理解和掌握这些基础知识对于成为一名合格的Java程序员至关重要。

Global site tag (gtag.js) - Google Analytics