【Java.Core】注解 - Annotation

注解(Annotation)为我们在代码中添加信息提供了一种形式化的方法,我们可以在稍后某个时刻方便地使用这些数据(通过解析注解来使用这些数据)。

注解是那些插入到源代码中用于工具处理的标签。这些标签可以在源码层次上进行处理,或者可以通过编译器将它们纳入到类文件中。

注解不会改变对编写的程序的编译方式。

为了能够受益于注解,需要选择一个处理工具,然后向你的处理工具可以理解的代码中插入注解,之后运用该处理工具。


注解的作用

注解常见的作用有以下几种:

  • 生成文档。这是最常见的,也是java最早提供的注解。常用的有@see @param @return等;
  • 跟踪代码依赖性,实现替代配置文件功能。如Spring中的基于注解配置。作用是减少配置;
  • 在编译时进行格式检查,如@Override放在方法前,如果这个方法并不是覆盖了超类方法,则编译时就能检查出;

标准注解

JDK5.0定义了7个注解接口。其中三个是规则接口,可以用它们来注释你的源代码中的项。其他四个是元注释,用于描述注解接口的行为属性。


正规注解

@Deprecated注解可以被添加到任何不在鼓励使用的条目上。当使用一个已过时的条目时,编译器将会发出警告。

@SuppressWarning注释会告知编译器阻止特殊类型的警告信息。

@Override注释只能应用到方法上,编译器会阻止具有这种注释的方法去覆盖一个来自于超类的方法。


元注解

@Target元注释

@Target元注释可以应用于一个注释,以限制该注释可以应用到哪些条目上。

下表显式了所有可能的取值情况,它们属于枚举类型ElementType。可以指定任意数量的元素类型,用括号括起来。

元素类型注释使用场合

ElementType ANNOTATION_TYPE

注释类型声明

ElementType PACKAGE

ElementType TYPE

类(包括enum)及接口(包括注解类型)

ElementType METHOD

方法

ElementType CONSTRUCTOR

构造器

ElementType FIELD

成员域(包括enum常量)

ElementType PARAMETER

方法或构造器参数

ElementType LOCAL_VARIABLE

本地变量

一条没有@Target限制的注解可以应用与任何条目上。

编译器只检查是否将一条注解应用到了某个允许的条目上,否则会导致一个编译器错误。

例如Spring中的注释@Controller定义:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {

	/**
	 * The value may indicate a suggestion for a logical component name,
	 * to be turned into a Spring bean in case of an autodetected component.
	 * @return the suggested component name, if any
	 */
	String value() default "";

}


@Retention元注解

@Retention元注释用于指定一条注释应该保留多长时间,只能将其指定为表中的任意值,默认为RetentionPolicy.CLASS.

保留规则描述

RetentionPolicy SOURCE

不包括在类文件*.class中的注释

RetentionPolicy CLASS

类文件中的注释,但是虚拟机不需要将它们载入

RetentionPolicy RUNTIME

类文件中的注释,并有虚拟机载入,通过反射API可以获得它们


@Documentd元注解

@Documentd元注释为像Javadoc这样的文档工具提供了一些提示。

@Inherited元注解

@Inherited元注解只能应用与对类的注解。如果一个类具有继承注解,那么它的所有子类都自动具有同样的注解。


注解语法

一个注解是由一个注解接口@interface来定义的:

modifier @interface AnnotationName{
	element declaration 1
	element declaration 2
	... 
	...
}

注解中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型,返回值类型只能是基本类型,Class,String,enum,注解类型,或由前面类型所组成的数组。可以通过default来声明参数的默认值。


每个元素具有下面这种形式:

type elementName();

或者

type elementName() default value;

例如:下面这个注解具有两个元素:assingedTo和severity。

public @interface BugReport{
	String assignedTo() default "[none]";
	int severity();
}

每个注解使用时都具有下面这种格式:

@AnnotationName(elementName1 = value1, elementName2 = value2, ... ...)

例如:

@BugReport(assignedTo = "Harry", severity=10)

元素的顺序无关紧要,下面这个注解和前面那个一样:

@BugReport(severity=10, assignedTo = "Harry")

如果某个元素的值并未指定,那么就使用声明的默认值。

默认值并不是和注解存储在一起的,它们是动态计算而来的。例如,如果将元素assignedTo的默认值更改为“[]”,然后重新编译BugReport接口,那么注解@BugReport(severity=10)将使用这个新的默认值。


简化注解的使用:

  • 标记注解:

如果没有指定元素,要么是因为注解中没有任何元素,要么是因为所有元素都使用默认值,那么就不需要使用圆括号,例如:

<span style="font-size:10px;">@BugReport</span>

  • 单值注解:

如果一个元素具有特殊的名字value,并且没有指定其他元素,那么就可以忽略掉这个元素名及等号这个符号,例如:

<span style="font-size:10px;">public @interface BugReport{
	String value();
}</span>

那么,可以将这个注解写成如下形式:

<span style="font-size:10px;">@BugReport("Harry")</span>


所有的注解接口隐式地扩展自java.lang.annotation.Annotation接口,这个接口是一个正规接口,不是一个注解接口。

无法扩展注解接口,所有的注解接口都直接扩展自java.lang.annotation.Annotation。


一个项目可以具有多个注解,只要它们属于不同的类型即可。当注解一个特定项的时候,不能多次使用同一个注解类型,例如:

<span style="font-size:10px;">@BugReport(severity=11)
@BugReport(severity=12)
void myMethod(){... ...}</span>

就是一种编译期错误。


读取/使用类中定义的注解

示例:

<span style="font-size:10px;">package annotation;

import java.lang.*;
import java.util.*;

import java.lang.annotation.*;

@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface TestA {
    String name();
    int id() default 0;
    Class<Long> gid();
}
</span>

<span style="font-size:10px;">package annotation;

import java.util.*;
import java.lang.*;

@TestA(name="type", gid=Long.class)
public class UserAnnotation {
    @TestA(name="param", id = 1, gid=Long.class)
    private Integer age;
    
    @TestA(name="construct", id = 2, gid=Long.class)
    public UserAnnotation(){
    	
    }
    
    @TestA(name="public method", id = 3, gid=Long.class)
    public void a(){
    	
    }
    
    @TestA(name="protected method", id = 4, gid= Long.class)
    protected void b(){
    	
    }
    
    @TestA(name="private method", id = 5, gid = Long.class)
    private void c(){
    	
    }
}
</span>

<span style="font-size:10px;">package annotation;

import java.lang.*;
import java.util.*;
import java.lang.annotation.*;
import java.lang.reflect.*;


public class ParseAnnotation {
    public static void parseTypeAnnotation() throws ClassNotFoundException{
    	Class clazz = Class.forName("annotation.UserAnnotation");
    	
    	Annotation[] annotations = clazz.getAnnotations();
    	for(Annotation annotation : annotations){
    		TestA testA = (TestA)annotation;
    		System.out.println("id = " + testA.id() + " name = " + testA.name() + " gid = " + testA.gid());
    	}
    }
    
    public static void parseMethodAnnotation(){
    	Method[] methods = UserAnnotation.class.getDeclaredMethods();
    	for (Method method : methods){
    		boolean hasAnnotation = method.isAnnotationPresent(TestA.class);
    		if (hasAnnotation){
    			TestA testA = (TestA)method.getAnnotation(TestA.class);
    			System.out.println("method = " + method.getName() + " id = " + testA.id() + " name = " + testA.name() + " gid = " + testA.gid());
    		}
    	}
    }
    
    public static void parseConstructAnnotation(){
    	Constructor[] constructors = UserAnnotation.class.getConstructors();
    	for (Constructor constructor : constructors){
    		boolean hasAnnotation = constructor.isAnnotationPresent(TestA.class);
    		if (hasAnnotation){
    			TestA testA = (TestA)constructor.getAnnotation(TestA.class);
    			System.out.println("constructor = " + constructor.getName() + " id = " + testA.id() + " name = " + testA.name() + " gid = " + testA.gid());
    		}
    	}
    }
    
    public static void main(String[] args) throws ClassNotFoundException{
    	parseTypeAnnotation();
    	parseMethodAnnotation();
    	parseConstructAnnotation();
    }
}
</span>

执行结果:

<span style="font-size:10px;">id = 0 name = type gid = class java.lang.Long
method = c id = 5 name = private method gid = class java.lang.Long
method = b id = 4 name = protected method gid = class java.lang.Long
method = a id = 3 name = public method gid = class java.lang.Long
constructor = annotation.UserAnnotation id = 2 name = construct gid = class java.lang.Long</span>







  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值