java注解细节
现在很多框架都使用注解了,典型的像Spring里面就可以看到大量的注解,比如@Service,@Controller这一类的都是注解。注解Annotation是java一项很重要的功能。下面就来整理一下关于注解的一些细节。
1.首先,什么是注解呢?
较为官方的解释是,注解是元数据,就是解释数据的数据。说得通俗一点,它是一种能够修饰类、变量、方法、参数等数据的元数据。以一个简单的例子,我们经常看到的一个注解是@Override。比如如下代码。
package com.xdx.learn;
public class Father {
public void func(){
System.out.println("hello");
}
}
class son extends Father{
@Override
public void func() {
System.out.println("hi");
}
}
可以看到在son类中,重写了(覆盖)父类的func()方法,我们用了一个@Override的注解去修饰这个方法。它起到的作用是告诉编译器,这个方法时覆盖父类的方法,假如我不小心把func写成了Func,编译器由于已经得知了我是想覆盖父类的func方法,就会提示我,父类并没有一个叫做Func的方法,我就会去检查,哦,原来是我写错了啊。
所以注解起到了一种修饰元数据的作用,被修饰过的元数据具有某些特性,这些特性将在程序编译、运行等时段被利用。具体是如何利用而起作用的,我们就不用去管了。提供该注解的提供者会搞定。
比如Spring中用@Resource注解的成员变量,将在该类实例化的时候,被注入到类的实例当中。而具体如何利用@Resource注解实现这一过程的,Spring帮我们做了。
2.注解的定义
我们来看看上面讲的@Resource
的注解的内部是如何定义的。
@Target({TYPE, FIELD, METHOD})
@Retention(RUNTIME)
public @interface Resource {
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
enum AuthenticationType {
CONTAINER,
APPLICATION
}
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default "";
String description() default "";
}
上述便是一个注解的定义,可以看到,这个注解都被两个元注解所修饰,分别是@Target和@Retention
先来看看@Target。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
它也被三个元注解来修饰,除了@Target和@Retention,还多出了一个@Documented。
事实上,总共有4种元注解,@Target、@Retention、@Documented、@Inherited。
@Target——指明该类型的注解可以注解的程序元素的范围(作用目标)。该元注解的取值可以为TYPE,METHOD,CONSTRUCTOR,FIELD等。如果Target元注解没有出现,那么定义的注解可以应用于程序的任何元素。由上述的@interface Target这个注解的定义,我们可以看到它的取值是一个枚举类型的数组。事实上,它们具体的值如下。
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
@Documented --类和方法的Annotation在缺省情况下是不出现在javadoc中的。如果使用@Documented修饰该Annotation,则表示它可以出现在javadoc中。
定义Annotation时,@Documented可有可无;若没有定义,则Annotation不会出现在javadoc中。
@Retention---指定注解的生命周期,也就是它能存活到什么时候,我们来看看@Retention的具体定义就知道。
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
然后我们看看RetentionPolicy 这个枚举类有哪些对象。
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
很清楚了,注解可以存活的生命周期有3种,编译阶段,存储在.class文件里面,还要就是到运行阶段。这里需要注意的是,只有当注解的Retention是RetentionPolicy.RUNTIME的时候,我们才可以通过反射获取方法或者类的注解信息。因为反射机制是在类加载完成以后的运行阶段发挥作用的。
@Inherited——如果一个类的注解(比如@A)被@Inherited元注解所标注,则这个类的子类可以继承该类的这个注解@A。注意的是,这种继承是针对类的注解,如果是方法的注解,则不需要用@Inherited。子类在继承父类的方法的同时也继承了这个方法的注解,除非你去重写方法。
回到@Resource注解,我们看到,定义一个注解需要用public @interface来修饰,并且被@Target、@Retention、@Documented(可选)、@Inherited(可选)这四个元注解所修饰。我们可以把注解看成一种特殊的类。看类内部,定义了很多方法,没有访问修饰符,没有方法体,没有参数,只有返回值类型。返回值可以带有默认值,如
String name() default "";
String lookup() default "";
Class<?> type() default java.lang.Object.class;
enum AuthenticationType { CONTAINER, APPLICATION }
AuthenticationType authenticationType() default AuthenticationType.CONTAINER;
boolean shareable() default true;
String mappedName() default ""; String description() default "";
需要记住的是这种方法定义的格式,无参,无方法体,事实上,我们可以理解成定义了一些成员变量,只不过这些成员变量名后面都加了一个(),并且可用default关键字来赋初值。
定义了成员变量以后,我们可以在用这个注解的时候给成员变量赋值。比如@Resource(name="baseDao")。
ps:如果注解中只有一个成员,且叫做value,我们在传入value的值的时候,就不用指定这个成员的名称的了。比如@Target(ElementType.ANNOTATION_TYPE)就属于这种情况。
3.就从一个注解类本身提供的信息而言,我们只能知道它的作用目标(从@Target元注解获悉),生命周期(@Retention元注解获悉),然后还能知道的是它的成员变量。除了从其他渠道(比如看源码注释)获悉这个注解的具体作用并加以应用(比如使用@Service标注一个Service类),仅从注解的定义文件你是看不出它有什么作用的。而我们对注解信息的编程也很有限,可以通过反射机制获取类,成员,或者方法的注解信息,注解的成员值等。比如下面代码。
package com.xdx.learn; import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//定义一个注解类,可作用于类和方法
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface Anno {
String value() default "";
} package com.xdx.learn; import java.lang.reflect.Method; @Anno("anno")
public class AnnoTest {
@Anno("anno")
public void func(){
System.out.println("hello");
}
public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException{
Class clz=Class.forName("com.xdx.learn.AnnoTest");
//反射获取类的注解信息
if(clz.getAnnotation(Anno.class)!=null){
Anno anno=(Anno) clz.getAnnotation(Anno.class);
System.out.println(anno.value());
System.out.println(anno.annotationType());
}
//反射获取方法的注解信息
Method method=clz.getDeclaredMethod("func", null);
if(method.isAnnotationPresent(Anno.class)){
Anno anno=method.getAnnotation(Anno.class);
System.out.println(anno.value());
System.out.println(anno.annotationType());
}
} }
上述代码运行的结果为:
anno
interface com.xdx.learn.Anno
anno
interface com.xdx.learn.Anno
java注解细节的更多相关文章
- Java注解--笔记
@Override标签的作用@Override是伪代码,所以是可写可不写的.它表示方法重写,写上会给我们带来好处. 1.可以当注释用,方便阅读. 2.告诉阅读你代码的人,这是方法的复写. 3.编译器可 ...
- java注解的自定义和使用
小伙伴们.今天我们来说说注解.标志@ .针对java不同版本来说,注解的出现是在jdk1.5 但是在jdk1.5版本使用注解必须继续类的方法的重写,不能用于实现的接口中的方法实现,在jdk1.6环境下 ...
- java注解自定义使用
Java提供了4种注解,专门负责新注解的创建: @Target: 表示该注解可以用于什么地方,可能的ElementType参数有:CONSTRUCTOR:构造器的声明FIELD:域声明(包括enum实 ...
- Java 注解概要
转载自:https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html(Java注解就跟C#的特性是一样的) 要深入学习注解,我们就必须能定 ...
- Java注解Annotation(一)
Java注解Annotation(一)——简介 这一章首先简单介绍一下注解,下一章会给出一个注解应用的DEMO. 1. 元注解 元注解的作用是负责注解其他的注解. JDK1.5中,定义了4个标准的me ...
- Java 注解指导手册 – 终极向导
原文链接 原文作者:Dani Buiza 译者:Toien Liu 校对:深海 编者的话:注解是java的一个主要特性且每个java开发者都应该知道如何使用它. 我们已经在Java Code Gee ...
- Java注解-元数据、注解分类、内置注解和自定义注解|乐字节
大家好,我是乐字节的小乐,上次说过了Java多态的6大特性|乐字节,接下来我们来看看Java编程里的注解. Java注解有以下几个知识点: 元数据 注解的分类 内置注解 自定义注解 注解处理器 Ser ...
- Java 注解指导手册(下)
9. 自定义注解 正如我们之前多次提及的,可以定义和实现自定义注解.本章我们即将探讨. 首先,定义一个注解: public @interface CustomAnnotationClass ...
- Java 注解指导手册(上)
编者的话:注解是java的一个主要特性且每个java开发者都应该知道如何使用它. 我们已经在Java Code Geeks提供了丰富的教程, 如Creating Your Own Java A ...
随机推荐
- 【Tesseract】Tesseract 的训练流程
在泰迪杯A题中,我刚刚接触了Tesseact,其中训练字库中遇到了较多的问题.所以在此记录一下,也当做一个笔记,省得以后忘记. 为了方便 ,将tif命名格式设为[lang].[fontname].ex ...
- JS获取DOM元素
1.childNodes:获取节点,不同浏览器表现不同: IE:只获取元素节点: 非IE:获取元素节点与文本节点: 解决方案:if(childNode.nodeName=="#text&qu ...
- c# 实体类生成工具
一个简单生成c#实体类的工具 源代码下载
- asp.net web api 版本控制
版本控制 版本控制的方法有很多,这里提供一种将Odata与普通web api版本控制机制统一的方法,但也可以单独控制,整合控制与单独控制主要的不同是:整合控制通过VersionController ...
- web前端-----第一弹html
HTML 初识 web服务本质 import socket def main(): sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s ...
- springMVC+spring+MyBatis(SSM)的简单配置
SSM(Spring+SpringMVC+MyBatis)框架集由Spring.SpringMVC.MyBatis三个开源框架整合而成,常作为数据源较简单的web项目的框架. 其中: Spring是一 ...
- IIS发布网站浏览之后看到的是文件目录 & Internal Server Error 处理程序“ExtensionlessUrlHandler-ISAPI-4.0_64bit”在其模块列表中有一个错误模块“IsapiModule” 解决方法 & App_global.asax.pduxejp_.dll”--“拒绝访问。 ”
Q:IIS发布网站浏览之后看到的是文件目录 A:它出现了一个说到.NET4.0 更高框架什么的错误,所以我将 .NTE CRL版本由4.0改为2.0了,改为2.0后就出现了只能浏览文件目录了.改为4. ...
- Hi,腾讯WeTest联合Unity官方打造的性能分析工具UPA,今日全新发布!
早在2016年ChinaJoy开始,WeTest曾受邀出席过Unity中国的线下性能场的活动,介绍我们的自动化框架和王者荣耀的故事.当时的活动很成功,期间我们收到了不少Unity开发者的好评,也为我们 ...
- python之列表(list)的使用方法介绍
python之列表(list)介绍 在python的使用过程中,我们经常会用到列表,然而经常会遇到疑惑,下面我将详细介绍下列表使用方法. 一.列表 列表经常用到的功能使增.删.改和查功能. 1. 增 ...
- 十一、Hadoop学习笔记————数据库与数据仓库
数据仓库是集成的面向主题的数据库的集合 面向主题主要是宏观上解决某一类问题,集合性指数据集 数据库主要处理用于事务处理,数据仓库用于分析处理,数据库适用于操作型数据,便于增删改查, 数据仓库则用于挖掘 ...