java注解

一、概念

   Annontation是Java5开始引入的新特征。中文名称一般叫注解也叫元注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。

  更通俗的意思是为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且是供指定的工具或框架使用的。

Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中

注解的语法比较简单,除了@符号的使用之外,它基本与Java固有语法一致。

 

一般是不需要自己去定义注解的,除非你要自己写框架类的东西,如果是,注解是配合反射一起用的,通过反射,可以根据class、field、method等对象拿到它上面标注的注解,然后根据有没有注解、注解的类型或注解上的参数的不同,来执行不同的操作。

 

 

 

 

二、原理

 

  Annotation其实是一种接口。通过Java的反射机制相关的API来访问annotation信息。相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。

annotation是不会影响程序代码的执行,无论annotation怎么变化,代码都始终如一地执行。

 

  Java语言解释器在工作时会忽略这些annotation,因此在JVM 中这些annotation是“不起作用”的,只能通过配套的工具才能对这些annontaion类型的信息进行访问和处理。

  Annotation与interface的异同

    1)、Annotation类型使用关键字@interface而不是interface。

这个关键字声明隐含了一个信息:它是继承了java.lang.annotation.Annotation接口,并非声明了一个interface

    2)、Annotation类型、方法定义是独特的、受限制的。

  Annotation 类型的方法必须声明为无参数、无异常抛出的。这些方法定义了annotation的成员:方法名成为了成员名,而方法返回值成为了成员的类型。而方法返回值类型必须为primitive类型、Class类型、枚举类型、annotation类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用 default和一个默认数值来声明成员的默认值,null不能作为成员默认值,这与我们在非annotation类型中定义方法有很大不同。

  Annotation类型和它的方法不能使用annotation类型的参数、成员不能是generic。只有返回值类型是Class的方法可以在annotation类型中使用generic,因为此方法能够用类转换将各种类型转换为Class。

    3)、Annotation类型又与接口有着近似之处。

 它们可以定义常量、静态成员类型(比如枚举类型定义)。Annotation类型也可以如接口一般被实现或者继承。

三、应用场合

  annotation一般作为一种辅助途径,应用在软件框架或工具中,在这些工具类中根据不同的 annontation注解信息采取不同的处理过程或改变相应程序元素(类、方法及成员变量等)的行为。

例如:Junit、Struts、Spring等流行工具框架中均广泛使用了annontion。使代码的灵活性大提高。

 

1.1 知识点

1.1.1 Java内置注解组成

 

注解的语法比较简单,除了@符号的使用以外,它基本上与java的固有语法一致,java内置了三种注解,定义在java.lang包中。

注解名称

描述

@Override

表示当前的方法定义将覆盖超类中的方法。

@Deprecated

使用了注解为它的元素编译器将发出警告,因为注解@Deprecated是不赞成使用的代码,被弃用的代码。

@SuppressWarnings

关闭不当编译器警告信息。

它可以有以下参数:

deprecation:过时的类或方法警告。

unchecked:执行了未检查的转换时警告。

fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告。

path:在类路径、源文件路径等中有不存在的路径时的警告。

serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告。

finally:任何 finally 子句不能完成时的警告。

all:关于以上所有情况的警告。

 

1.1.2 如何使用注解

注解的实例代码如下:

public class Dog {

/**

 * 一个普通的方法,让此方法变成弃用方法

 */

@Deprecated

public void run() {

}

/**

 * 方法里有未使用的变量i,在eclipse中有警告提示,

 * 如果我们想在警告去掉,可以使用@SuppressWarnings注解。

 *

 */

@SuppressWarnings({"all"})

public void eat() {

int i = 5;

}

/**

 * 重写Object类中的toString()方法,如果不加@Override

 * 本意是想重写toString(),但如果方法名称写错了也不会报错,

 * eclipse认为这是在子类里添加了一个新方法,如果加上@Override

 * 這就是重寫,父類中必須有這樣的方法。

 */

@Override

public String toString() {

return super.toString();

}

}

 

1.1.3 创建新注解

和创建一个自定义的类一样,我们不仅可以使用别人写好的类,我们也可以创建自已需要的类,注解也一样,也可以创建系统中不存在的注解。在进行创建新注解时,需要用到原注解,原注解是专门负责新注解的创建的。

 

原注解共有四个,如下描述:

@Retention

它是被定义在一个注解类的前面,用来说明该注解的生命周期。

它有以下参数:

RetentionPolicy.SOURCE :指定注解只保留在一个源文件当中。

RetentionPolicy.CLASS :指定注解只保留在一个 class 文件中。

RetentionPolicy.RUNTIME :指定注解可以保留在程序运行期间。

 

@Target

它是被定义在一个注解类的前面,用来说明该注解可以被声明在哪些元素前。

它有以下参数:

ElementType.TYPE :说明该注解只能被声明在一个类前。

ElementType.FIELD :说明该注解只能被声明在一个类的字段前。

ElementType.METHOD :说明该注解只能被声明在一个类的方法前。

ElementType.PARAMETER :说明该注解只能被声明在一个方法参数前。

ElementType.CONSTRUCTOR :说明该注解只能声明在一个类的构造方法前 。

ElementType.LOCAL_VARIABLE :说明该注解只能声明在一个局部变量前。

ElementType.ANNOTATION_TYPE :说明该注解只能声明在一个注解类型前 。

ElementType.PACKAGE :说明该注解只能声明在一个包名前。

 

@Documented

将注解包含在Javadoc中。

 

@Inherited

允许子类继承父类中的注解。

 

先来看一下如何编写一个最简单的注解类:

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

@Retention(RetentionPolicy.CLASS)

@Target({ElementType.FIELD, ElementType.METHOD})

@Documented

@Inherited

public @interface Fruit {

 

}

 

通过此注解返回给我们的信息有:

² 当在一个注解类前定义了一个 @Retetion(RetentionPolicy.CLASS) 的注解,那么说明该注解只保留在一个 class 文件当中,当加载 class 文件到内存时,虚拟机会将注解去掉,从而在程序中不能访问。

² 说明该注解只能被声明在一个类的属性和方法前。注意,如果注解类同时可以用到类和方法前,需要用“{}”引起来编写。

² 在生成文档时将注解包含在Javadoc中。

² 允许子类继承父类中的注解。

 

除了@符号,注解很像是一个接口。定义注解的时候需要用到元注解,上面用到了@Target@RetentionPolicy@Documented@Inherited四个原注解。

1.1.4 注解定义

1、注解可以有哪些成员?

注解和接口相似,它只能定义 final 静态属性和公共抽象方法。

 

2、注解的方法?

1. 方法前默认会加上 public abstract

2. 在声明方法时可以定义方法的默认返回值。

例如 :

String color() default "blue";

String[] color() default {"blue", "red",......}

 

3、方法的返回值可以有哪些类型 ?

八种基本类型, String Class 、枚举、注解及这些类型的数组。

1.1.5 注解生命周期

一个注解可以有三个生命周期,它默认的生命周期是保留在一个 CLASS 文件,但它也可以由一个@Retetion的元注解指定它的生命周期。

java 源文件

当在一个注解类前定义了一个@Retetion(RetentionPolicy.SOURCE) 的注解,那么说明该注解只保留在一个源文件当中,当编译器将源文件编译成 class 文件时,它不会将源文件中定义的注解保留在 class 文件中。

class 文件中

当在一个注解类前定义了一个 @Retetion(RetentionPolicy.CLASS) 的注解,那么说明该注解只保留在一个 class 文件当中,当加载 class 文件到内存时,虚拟机会将注解去掉,从而在程序中不能访问。

程序运行期间

当在一个注解类前定义了一个 @Retetion(RetentionPolicy.RUNTIME) 的注解,那么说明该注解在程序运行期间都会存在内存当中。此时,我们可以通过反射来获得定义在某个类上的所有注解。

1.1.6 注解的使用

在注解中一般会有一些元素以表示某些值。注解的元素看起来就像接口的方法,唯一的区别在于可以为其制定默认值。没有元素的注解称为标记注解,上面的@Fruit就是一个标记注解。

 

注解的可用的类型包括以下几种:所有基本类型、StringClassenumAnnotation、以上类型的数组形式。

 

对注解元素的要求:

ü 元素不能有不确定的值,即要么有默认值,要么在使用注解的时候提供元素的值。

ü 元素不能使用null作为默认值。

ü  注解元素必须有确定的值,要么在定义注解的默认值中指定,要么在使用注解时指定,非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。这个约束使得处理器很难表现一个元素的存在或缺失的状态,因为每个注解的声明中,所有元素都存在,并且都具有相应的值,为了绕开这个约束,我们只能定义一些特殊的值,例如空字符串或者负数,一次表示某个元素不存在,在定义注解时,这已经成为一个习惯用法。

ü 注解在只有一个元素且该元素的名称是value的情况下,在使用注解的时候可以省略“value=”,直接写需要的值即可。

 

继续使用刚才的注解类,给里面添加注解元素,一共添加三个,一个是常量元素,两个是普通元素,两个普通元素一个有默认值,一个没有默认值。

import java.lang.annotation.Documented;

import java.lang.annotation.ElementType;

import java.lang.annotation.Inherited;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

 

/**

 * 注解中有三个元素,一个是常量id,一个是sheel,一个是shareshare有默认值。

 * @author Administrator

 *

 */

@Retention(RetentionPolicy.CLASS)

@Target({ElementType.TYPE, ElementType.METHOD})

@Documented

@Inherited

public @interface Fruit {

public final int count = 1;

public int sheel();

public String share() default "";

}

 

定义了注解,必然要去使用注解。对@Fruit类进行的使用:

@Fruit(sheel=1)

public class Apple {

 

}

 

因为在编写@Fruit时没有给sheel默认值,所以在使用@Fruit必须要给此元素赋值。有默认值的,我们可以对其进行修改:

@Fruit(sheel=1,share="")

public class Apple {

 

}

 

注意:常量不可以进行修改。

 

使用注解最主要的部分在于对注解的处理,那么就会涉及到注解处理器。从原理上讲,注解处理器就是通过反射机制获取被检查方法上的注解信息,然后根据注解元素的值进行特定的处理。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值