Java中的注解

1、 简介

Annotation(注解)就是Java提供了一种为程序元素关联任何信息或任何元数据(metadata)的途径和方法。它是一个接口,程序可以通过反射来获取指定程序元素的Annotion对象,然后通过Annotion对象来获取注解里面的元数据。

Annotation是代码里的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。通过使用Annotation,开发人员可以在不改变原有逻辑的情况下,在源文件中嵌入一些补充的信息。代码分析工具、开发工具和部署工具可以通过这些补充信息进行验证、处理或者进行部署。

Annotation提供了一种为程序元素(包、类、构造器、方法、成员变量、参数、局域变量)设置元数据的方法。Annotation不能运行,它只有成员变量,没有方法。Annotation跟public、final等修饰符的地位一样,都是程序元素的一部分,Annotation不能作为一个程序元素使用。

使用注解有一个基本的规则:即Annotation不能影响程序代码的执行,无论增加、删除Annotation,代码都始终如一的执行。

2、注解的作用

(1)生成文档。这是最常见的,也是Java最早提供的注解。常用的有@see @param @return 等。
(2)跟踪代码依赖性,实现替代配置文件功能。比较常见的是spring 2.5开始的基于注解配置。作用就是减少配置。现在的框架基本都使用了这种配置来减少配置文件的数量。
(3)在编译时进行格式检查。如@override放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

3、Annotation和Annotation类型说明

(1)Annotation

Annotation的行为十分类似public、final这样的修饰符。每个Annotation具有一个名字和成员个数>=0。每个Annotation的成员具有被称为name=value对的名字和值(就像javabean一样),name=value装载了Annotation的信息。

(2)Annotation类型

Annotation类型定义了Annotation的名字、类型、成员默认值。一个Annotation类型可以说是一个特殊的java接口,它的成员变量是受限制的,而声明Annotation类型时需要使用新语法。当我们通过java反射api访问Annotation时,返回值将是一个实现了该annotation类型接口的对象,通过访问这个对象我们能方便的访问到其Annotation成员。

4、注解的分类

根据注解的使用方法和用途,我们可以将Annotation分为三类:
(1)JDK内置系统注解
(2)元注解
(3)自定义注解

5、JDK内置系统注解

注解的语法比较简单,除了@符号的使用外,他基本与Java固有的语法一致,JavaSE中内置三个标准内置注解,定义在java.lang中:
    

@Override //用于修饰此方法覆盖了父类的方法
@Deprecated //用于修饰已经过时的方法
@SuppressWarnnings //用于通知java编译器禁止特定的编译警告

5.1 @Override

@Override 是一个标记注解类型,它被用作标注方法,用来限定重写父类方法。它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种Annotation在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。这个annotaton常常在我们试图覆盖父类方法而又写错了方法名时发挥威力。使用方法极其简单:在使用此annotation时只要在被修饰的方法前面加上@Override即可。

@Override注解只能用于方法,不能用于其他。

5.2 @Deprecated

@Deprecated也是一个标记注解,用来标记已过时。当一个类型或者类型成员使用@Deprecated修饰的话,编译器将不鼓励使用这个被标注的程序元素。而且这种修饰具有一定的 “延续性”,如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为 @Deprecated,但编译器仍然要报警。

值得注意,@Deprecated这个annotation类型和javadoc中的 @deprecated这个tag是有区别的:前者是java编译器识别的,而后者是被javadoc工具所识别用来生成文档(包含程序成员为什么已经过 时、它应当如何被禁止或者替代的描述)。
  
下面代码使用了@Deprecated注解标示方法过期,代码如下:

public class Test {
    /**
     * @deprecated 该方法已经过期,不推荐使用
     */
    @Deprecated
    public void show(){
        System.out.println("111");
    }

    public void show(int id){
        if(id == 1){
            System.out.println("222");
        } else {
            System.out.println("333");
        }
    }

    public static void main(String[] args) {
        Test test = new Test();
        test.show();//被标记不推荐使用
        test.show(1);
    }
}

5.3 @SuppressWarnnings

@SuppressWarnings被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告,抑制编译器警告

@SuppressWarning不是一个标记注解。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。常见的警告名为下:

unchecked //执行了未检查的转换时的警告。例如当使用集合时没有用泛型来指定集合的类型
finally //finally子句不能正常完成时的警告
fallthrough //当switch程序块直接通往下一种情况而没有break时的警告
deprecation //使用了弃用的类或者方法时的警告
seriel //在可序列化的类上缺少serialVersionUID时的警告
path //在类路径、源文件路径等中有不存在的路径时的警告
all //对以上所有情况的警告

如:

@SuppressWarnings("unchecked") ///告诉编译器忽略unchecked 警告信息,如使用List,ArrayList等未进行参数化产生的警告信息。

@SuppressWarnings("serial") //如果编译器出现这样的警告信息:The serializable class WmailCalendar does not declare a static final serialVersionUID field of type long使用这个注释将警告信息去掉。

@SuppressWarnings("deprecation") //如果使用了使用@Deprecated注释的方法,编译器将出现警告信息。使用这个注释将警告信息去掉。

@SuppressWarnings("unchecked", "deprecation") //告诉编译器同时忽略unchecked和deprecation的警告信息。

@SuppressWarnings(value={"unchecked", "deprecation"}) //等同于@SuppressWarnings("unchecked", "deprecation")

6、元注解

元注解的作用就是负责注解其他注解。

1@Target2@Retention3@Documented4@Inherited

这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。

6.1 @Target

@Target说明了Annotation所修饰的对象范围,Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。用于描述注解的使用范围(即:被描述的注解可以用在什么地方)。它的取值(ElementType)有:

ElementType.TYPE:能修饰类、接口或枚举类型

ElementType.FIELD:能修饰成员变量

ElementType.METHOD:能修饰方法

ElementType.PARAMETER:能修饰参数

ElementType.CONSTRUCTOR:能修饰构造器

ElementType.LOCAL_VARIABLE:能修饰局部变量

ElementType.ANNOTATION_TYPE:能修饰注解

ElementType.PACKAGE:能修饰包

如:

@Target({ ElementType.FIELD, ElementType.METHOD })
public @interface Test {

    String name = null;

    public String getName();
}

6.2 @Retention

@Retention用于指定Annotation可以保留多长时间。@Retention包含一个名为“value”的成员变量,该value成员变量是RetentionPolicy枚举类型。使用@Retention时,必须为其value指定值。value成员变量的值只能是如下3个:

RetentionPolicy.SOURCE:Annotation只保留在源代码中,编译器编译时,直接丢弃这种Annotation。

RetentionPolicy.CLASS:编译器把Annotation记录在class文件中。当运行Java程序时,JVM中不再保留该Annotation。

RetentionPolicy.RUNTIME:编译器把Annotation记录在class文件中。当运行Java程序时,JVM会保留该Annotation,程序可以通过反射获取该Annotation的信息。

如:

//name=value形式
//@Retention(value=RetentionPolicy.RUNTIME)

//直接指定
@Retention(RetentionPolicy.RUNTIME)
public @interface Test{
    String name() default "111";
}

如果Annotation里有一个名为“value“的成员变量,使用该Annotation时,可以直接使用XXX(val)形式为value成员变量赋值,无须使用name=val形式。

6.3 @Documented

如果定义注解A时,使用了@Documented修饰定义,则在用javadoc命令生成API文档后,所有使用注解A修饰的程序元素,将会包含注解A的说明,即将此注解包含在Javadoc中。Documented是一个标记注解,没有成员。

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Test {
    public String name() default "fieldName";
    public String setFuncName() default "setField";
    public String getFuncName() default "getField";
    public boolean defaultDBValue() default false;
}

6.4 @Inherited

@Inherited指定Annotation具有继承性。它是一个标记注解,阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

7、自定义注解

使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用来声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。自定义注解格式:

public @interface 注解名 {定义体}

7.1 自定义注解参数的可支持数据类型

(1)所有基本数据类型(int,float,boolean,byte,double,char,long,short)
(2)String类型
(3)Class类型
(4)enum类型
(5)Annotation类型
(6)以上所有类型的数组

7.2 Annotation类型里面的参数设定

(1)只能用public或默认(default)这两个访问权修饰。例如:

String value();//这里把方法设为defaul默认类型 

(2)参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String, Enum, Class, annotations等数据类型,以及这一些类型的数组。例如:

String value();//这里的参数成员就为String

(3)如果只有一个参数成员,最好把参数名称设为”value”,后加小括号。例如下面的例子FruitName注解就只有一个参数成员。简单的自定义注解和使用注解实例:

/**
 * 名称注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
 @interface FruitName {
    String value() default "";
}

/**
 * 颜色注解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface FruitColor {
    /**
     * 颜色枚举
     */
    public enum Color{ YELLOW,RED,GREEN};

    /**
     * 颜色属性
     * @return
     */
    Color fruitColor() default Color.GREEN;

}

class Apple {

    @FruitName("Apple")
    private String appleName;

    @FruitColor(fruitColor = FruitColor.Color.RED)
    private String appleColor;

}

注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此,使用空字符串或0作为默认值是一种常用的做法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值