注解

注解

本文写作目的是为了做笔记,部分概念性资料来源于网络,如有侵权,请联系我删除

什么是注解

Java 注解(Annotation)又称 Java 标注,是JDK5.0引入的一种注释机制。
Java 语言中的类、方法、变量、参数和包等都可以被标注。和 Javadoc 不同,Java 标注可以通过反射获取标注内容。在编译器生成类文件时,标注可以被嵌入到字节码中。Java 虚拟机可以保留标注内容,在运行时可以获取到标注内容 。 当然它也支持自定义 Java 标注。

注解的作用

  1. 用来充当注释作用(仅仅是一个文字说明) 如@Deprecated写在某个方法上表示该方法已过期不推荐使用,但是你想用也可以用
  2. 用来做代码的检测(验证) 如@Override
  3. 可以携带一些信息

注解可携带的信息的类型

注解可以携带信息,也可以不携带。如果携带信息,则必须是如下的类型

  1. 基本数据类型
  2. String类型
  3. 枚举类型
  4. 注解类型
  5. 数组类型(数组内的数据必须是如上的4种类型)

自定义注解

一个简单的示例

package study.annotation;

import static java.lang.annotation.ElementType.*;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 注解学习
 * @author Administrator
 */
@Target({FIELD, METHOD})
@Retention(RetentionPolicy.SOURCE)
@Inherited
@Documented
public @interface TestAnnotation01 {
	// 注解的方法
	public abstract String test() default "aaa";
}

注意:

  1. 注解使用@interface声明,修饰符仅允许使用public

  2. 注解的定义形式一般如下

    modifier type attributeName() default "default value";

    示例如下

    public abstract String test() default "aaa";

    1. 上面的attributeName称之为注解的方法(也有人称之为注解的属性,但是无论是从它的组成形式上来看还是它可以被public abstract修饰来看,这个东西更像是一个方法。另外还有一点可以佐证这个观点,那就是当你利用反射技术来获取注解里面的值时,你是通过class.getMethod方法来获取到获取attributeName的,而不是class.getField。可以从文章最后的示例里面找到
    2. 上面的type称之为注解的类型,仅允许使用基本类型,字符串,枚举,注解或其一维数组
    3. 注解的方法前面仅允许使用public abstract修饰,所以也可以省略不写
    4. 注解的方法可以有默认值,也可以不给默认值,默认值使用default关键字说明
  3. 自定义的注解需要使用元注解说明,如下

    @Target({FIELD, METHOD})
    @Retention(RetentionPolicy.SOURCE)
    @Inherited
    @Documented
    

元注解

元注解是用来说明注解的注解(Java已经提供好了的),每个自定义的注解都需要用元注解来说明其自身的一些特性。元注解存于java.lang.annotation包下,一共有四个。分别是@Target@Retention@Inherited@Documented

@Target

定义了注解的作用目标,源码为

@Documented  
@Retention(RetentionPolicy.RUNTIME)  
@Target(ElementType.ANNOTATION_TYPE)  
public @interface Target {  
    ElementType[] value();  
} 

使用@Target需要给其传递一个ElementType(枚举)类型的数组,ElementType的每一个成员都标识着一个作用目标,详情如下

// 接口、类、枚举、注解
@Target(ElementType.TYPE)

// 字段、枚举的常量
@Target(ElementType.FIELD)

// 方法
@Target(ElementType.METHOD)

// 方法参数
@Target(ElementType.PARAMETER)

// 构造函数
@Target(ElementType.CONSTRUCTOR)

//局部变量
@Target(ElementType.LOCAL_VARIABLE)

//注解
@Target(ElementType.ANNOTATION_TYPE)

// 包
@Target(ElementType.PACKAGE)

@Retention

定义了注解的保留策略,即注解可以被保留在那个阶段

我们都知道Java代码的执行过程如下

源代码文件--->编译--->字节码文件--->加载--->内存执行
这个过程在@Retention注解里对应如下
SOURCE             CLASS  			   RUNTIME

对应如下

// 注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.SOURCE)

// 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.CLASS)

// 注解会在class字节码文件中存在,在运行时可以通过反射获取到
@Retention(RetentionPolicy.RUNTIME)

@Inherited

说明子类可以继承父类中的该注解

@Document

说明该注解将被包含在javadoc

使用注意

  1. 如果注解中只有一个方法,并且方法名为value,则在使用的时候可以不传方法名,只传递值即可
  2. 如果传递的是一个数组,数组内只有一个元素,则可以省略{}
  3. 如果注解中的方法为两个以上,则每一个方法名都需要写

利用反射技术获取注解里的值

一个简单的示例,需要一个注解类TestAnnotation01、一个普通的Java类Person以及一个main方法

注解类TestAnnotation01

package study.annotation;

import static java.lang.annotation.ElementType.*;

import java.lang.annotation.Documented;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 注解学习
 * @author Administrator
 */
@Target({FIELD, METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface TestAnnotation01 {
	String[] value();
}

Person

package study.annotation;

public class Person {
	@TestAnnotation01({"lmw", "18", "男"})
	private String name;
	
}

main方法

package study.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 利用反射技术获取Person类字段上的注解里面的值
 * @author Administrator
 */
public class TestMain {
	public static void main(String[] args) {
		try {
			// 1.获取Person类的类类型
			Class clazz = Person.class;
			// 2.获取Person类的属性对象
			Field field = clazz.getDeclaredField("name");
			// 3.获取字段上的注解对象
			Annotation a = field.getAnnotation(TestAnnotation01.class);
			// 4.获取注解的类类型
			Class aClazz = a.getClass();
			// 5.获取注解里的方法
			Method method = aClazz.getMethod("value");
			// 6.使用invoke方法执行value方法获取返回值
			String[] values = (String[])method.invoke(a);
			// 7.展示values的值
			for(String value:values) {
				System.out.println(value);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
posted @ 2019-11-11 18:55  xxx从入门到入坟  阅读(286)  评论(0)    收藏  举报