您的位置:首页 > 编程语言 > Java开发

深入理解Java:注解(Annotation)自定义注解入门

2017-07-05 00:00 405 查看
深入理解Java:注解(Annotation)自定义注解入门

  要深入学习注解,我们就必须能定义自己的注解,并使用注解,在定义自己的注解之前,我们就必须要了解Java为我们提供的元注解和相关定义注解的语法。

元注解:

  元注解的作用就是负责注解其他注解。Java5.0定义了4个标准的meta-annotation类型,它们被用来提供对其它 annotation类型作说明。Java5.0定义的元注解:
    1.@Target,
    2.@Retention,
    3.@Documented,
    4.@Inherited
  这些类型和它们所支持的类在java.lang.annotation包中可以找到。下面我们看一下每个元注解的作用和相应分参数的使用说明。

  @Target:

   @Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在Annotation类型的声明中使用了target可更加明晰其修饰的目标。

  作用:用于描述注解的使用范围(即:被描述的注解可以用在什么地方)

  取值(ElementType)有:

    1.CONSTRUCTOR:用于描述构造器
    2.FIELD:用于描述域
    3.LOCAL_VARIABLE:用于描述局部变量
    4.METHOD:用于描述方法
    5.PACKAGE:用于描述包
    6.PARAMETER:用于描述参数
    7.TYPE:用于描述类、接口(包括注解类型) 或enum声明

  使用实例:  



@Target(ElementType.TYPE)
public @interface Table {
/**
* 数据表名称注解,默认值为类名称
* @return
*/
public String tableName() default "className";
}

@Target(ElementType.FIELD)
public @interface NoDBColumn {

}




  注解Table 可以用于注解类、接口(包括注解类型) 或enum声明,而注解NoDBColumn仅可用于注解类的成员变量。

  @Retention:

  @Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对 Annotation的“生命周期”限制。

  作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)

  取值(RetentionPoicy)有:

    1.SOURCE:在源文件中有效(即源文件保留)
    2.CLASS:在class文件中有效(即class保留)
    3.RUNTIME:在运行时有效(即运行时保留)

  Retention meta-annotation类型有唯一的value作为成员,它的取值来自java.lang.annotation.RetentionPolicy的枚举类型值。具体实例如下:



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




  Column注解的的RetentionPolicy的属性值是RUTIME,这样注解处理器可以通过反射,获取到该注解的属性值,从而去做一些运行时的逻辑处理

  @Documented:

  [b]@[/b]Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。Documented是一个标记注解,没有成员。



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




  @Inherited:

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

  注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法并不从它所重载的方法继承annotation。

  当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。

  实例代码:



/**
*
* @author peida
*
*/
@Inherited
public @interface Greeting {
public enum FontColor{ BULE,RED,GREEN};
String name();
FontColor fontColor() default FontColor.GREEN;
}




自定义注解:

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

  定义注解格式:
  public @interface 注解名 {定义体}

  注解参数的可支持数据类型:

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

  Annotation类型里面的参数该怎么设定:
  第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型;   
  第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和 String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;  
  第三,如果只有一个参数成员,最好把参数名称设为"value",后加小括号.例:下面的例子FruitName注解就只有一个参数成员。

  简单的自定义注解和使用注解实例:



package annotation;

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

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






package annotation;

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

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

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

}






package annotation;

import annotation.FruitColor.Color;

public class Apple {

@FruitName("Apple")
private String appleName;

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

public void setAppleColor(String appleColor) {
this.appleColor = appleColor;
}
public String getAppleColor() {
return appleColor;
}

public void setAppleName(String appleName) {
this.appleName = appleName;
}
public String getAppleName() {
return appleName;
}

public void displayName(){
System.out.println("水果的名字是:苹果");
}
}




注解元素的默认值:

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



1 package annotation;
2
3 import java.lang.annotation.Documented;
4 import java.lang.annotation.ElementType;
5 import java.lang.annotation.Retention;
6 import java.lang.annotation.RetentionPolicy;
7 import java.lang.annotation.Target;
8
9 /**
10  * 水果供应者注解
11  * @author peida
12  *
13  */
14 @Target(ElementType.FIELD)
15 @Retention(RetentionPolicy.RUNTIME)
16 @Documented
17 public @interface FruitProvider {
18     /**
19      * 供应商编号
20      * @return
21      */
22     public int id() default -1;
23
24     /**
25      * 供应商名称
26      * @return
27      */
28     public String name() default "";
29
30     /**
31      * 供应商地址
32      * @return
33      */
34     public String address() default "";
35 }




  定义了注解,并在需要的时候给相关类,类属性加上注解信息,如果没有响应的注解信息处理流程,注解可以说是没有实用价值。如何让注解真真的发挥作用,主要就在于注解处理方法,下一步我们将学习注解信息的获取和处理!



分类: java

标签: 深入理解Java, Java注解, Annotation, 元注解, 自定义注解

好文要顶 关注我 收藏该文








peida
关注 - 3
粉丝 - 3166

+加关注

75

0

« 上一篇:深入理解Java:注解(Annotation)基本概念
» 下一篇:深入理解Java:注解(Annotation)--注解处理器

posted @ 2013-04-24 08:44 peida 阅读(394986) 评论(29) 编辑 收藏

评论列表

#1楼 2013-04-24 12:16 Never_say

写的很好,我对这块也不熟,关注一下

支持(0)反对(0)

#2楼 2013-04-24 13:16 风之翼ASD

讲得很好,非常感谢分享,还有下一篇呢?不会用Annotation呢!

支持(0)反对(0)

#3楼 2013-04-26 10:45 遗忘海岸

View Code
点不开饿

支持(0)反对(0)

#4楼[楼主] 2013-04-26 18:00 peida

@ 遗忘海岸
已经修复了!谢谢提醒

支持(0)反对(0)

#5楼 2013-08-26 15:28 ffshi2010

@FruitName("Apple")
private String appleName;
@FruitName这个是类注解,标识在属性上编译不通过

支持(0)反对(0)

#6楼 2013-08-26 15:49 ffshi2010

@FruitName("Apple")
private String appleName;
@FruitName这个是类注解,标识在属性上编译不通过

不好意思,我测试时候把FruitName注解修饰范围声明为
@Target(ElementType.TYPE)这个了

支持(1)反对(0)

#7楼 2013-12-18 23:54 mr_nop

这个关于注解的系列非常详细,非常好。赞一个。

支持(0)反对(0)

#8楼 2014-07-17 17:51 530247683

很喜欢博主的文章,刚刚用豆约翰博客备份专家备份了您的全部博文。

支持(0)反对(0)

#9楼 2014-10-27 11:00 宁静致远_

赞一个 谢谢楼主

支持(0)反对(0)

#10楼 2015-02-23 15:36 Thorton

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

感谢楼主,写的很好

支持(0)反对(0)

#11楼 2015-06-29 09:54 32156714

内容非常详细, 很好 , 感谢楼主

支持(1)反对(0)

#12楼 2015-07-02 17:03 草之梦

菜鸟学习

支持(0)反对(0)

#13楼 2015-07-09 10:46 白Rime

简单易懂

支持(0)反对(0)

#14楼 2015-07-16 12:12 Kevin丢

博举真是好银啊 简单易通 学习了 mark了

支持(0)反对(0)

#15楼 2015-08-27 11:11 R星月

写的很好,正用到

支持(0)反对(0)

#16楼 2016-01-10 21:18 踹伤心

写的很好,受益匪浅。。。感谢!!!

支持(0)反对(0)

#17楼 2016-02-24 14:14 lelema

写得非常好,谢谢博主

支持(0)反对(0)

#18楼 2016-02-25 17:54 谢天铎

这篇文章比较浅
更深入可以看注解系列的三篇文章
http://blog.csdn.net/duo2005duo/article/details/50505884
http://blog.csdn.net/duo2005duo/article/details/50511476
http://blog.csdn.net/duo2005duo/article/details/50541281

支持(0)反对(0)

#19楼 2016-06-16 21:08 搬砖工的奋斗史

楼主 请问下 我在源码中看到这个注解是什么 target({ElementType.ANNOTATION_TYPE})

支持(0)反对(0)

#20楼 2016-07-22 00:44 netwelfare

注解分为元注解和注解,元注解部分需要仔细阅读JDK源码才能掌握,可以参看这篇文章的介绍:《注解系列知识总结》

支持(0)反对(0)

#21楼 2016-08-25 13:21 苏城

这个 用处 大不主要运在那些场景

支持(0)反对(0)

#22楼 2016-10-25 15:46 fanlion

@ 苏城
自定义注解可以用在spring环境下

支持(0)反对(0)

#23楼 2016-11-15 13:53 栀子花的味道

写的很棒,感谢楼主。

支持(0)反对(0)

#24楼 2016-12-16 15:44 CrazyKid

很好,加油。

支持(0)反对(0)

#25楼 2017-04-05 22:27 时间de玩物

赞一个,刚学完有点蒙,看完清楚了许多

支持(0)反对(0)

#26楼 2017-05-21 17:07 大金镯子

感觉像翻译来的

支持(0)反对(0)

#27楼 2017-05-24 15:49 Dulk

受教了,感谢。

支持(0)反对(0)

#28楼 2017-05-24 18:18 丁青松

谢谢博主的分享

支持(0)反对(0)

#29楼 2017-06-25 14:23 凝荷

谢谢博主分享,我转载到我的博客了

支持(0)反对(0)

刷新评论刷新页面返回顶部

注册用户登录后才能发表评论,请 登录 或 注册,访问网站首页。

【推荐】50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
【免费】从零开始学编程,开发者专属实验平台免费实践!





最新IT新闻:
· 格力接班人之困:并非没有 而在确定
· 百度度秘事业部总经理景鲲:DuerOS是AI时代的安卓系统
· 共享电单车这碗温吞水,还有沸腾的可能吗?
· 核心资产抵押给孙宏斌,贾跃亭可能只剩下一个梦
· 小米与诺基亚达成专利合作 收购部分诺基亚专利资产
» 更多新闻...





最新知识库文章:

· 小printf的故事:什么是真正的程序员?
· 程序员的工作、学习与绩效
· 软件开发为什么很难
· 唱吧DevOps的落地,微服务CI/CD的范本技术解读
· 程序员,如何从平庸走向理想?

» 更多知识库文章...

公告




欢迎你 访问本站

昵称:peida
园龄:9年1个月
粉丝:3166
关注:3

+加关注

<2013年4月>
31123456
78910111213
14151617181920
21222324252627
2829301234
567891011

搜索

常用链接

我的随笔

我的评论

我的参与

最新评论

我的标签

最新随笔

1. Maven编译jar出现:无法确定 T 的类型参数的异常的原因和处理方案

2. Guava学习笔记目录

3. Guava学习笔记:Range

4. Guava学习笔记:EventBus

5. Guava学习笔记:Guava cache

6. Guava学习笔记:Guava新集合-Table等

7. Guava学习笔记:Guava新增集合类型-Bimap

8. Guava学习笔记:Guava新增集合类型-Multimap

9. Guava学习笔记:Guava新增集合类型-Multiset

10. Guava学习笔记:Immutable(不可变)集合

我的标签

linux命令(62)

每日一linux命令(62)

linux(58)

敏捷个人(22)

敏捷结果练习(20)

Guava(15)

Guava学习笔记(15)

linux网络命令(10)

设计模式(9)

linux性能分析(5)

更多

随笔分类(174)

.net3.x(WF/Linq/WCF)(12)

ASP.NET(11)

Go语言

IT人健康(1)

java(22)

JavaScript+jQuery(3)

linux(60)

产品设计/用户体验(1)

敏捷个人(33)

设计模式(22)

数据库SQL(5)

系统架构

项目管理(2)

重构(2)

随笔档案(198)

2015年1月 (1)

2013年8月 (2)

2013年7月 (8)

2013年6月 (6)

2013年5月 (1)

2013年4月 (5)

2013年3月 (10)

2013年2月 (2)

2013年1月 (3)

2012年12月 (25)

2012年11月 (22)

2012年10月 (20)

2012年9月 (20)

2012年8月 (3)

2011年12月 (1)

2011年11月 (2)

2011年10月 (1)

2011年8月 (1)

2011年7月 (1)

2010年7月 (1)

2010年6月 (1)

2010年5月 (1)

2009年5月 (3)

2009年4月 (1)

2009年3月 (2)

2009年2月 (5)

2008年12月 (2)

2008年11月 (10)

2008年10月 (2)

2008年9月 (3)

2008年8月 (8)

2008年7月 (6)

2008年6月 (15)

2008年5月 (4)

友情连接

积分与排名

积分 - 391160

排名 - 331

最新评论

1. Re:深入理解Java:注解(Annotation)基本概念

Annotation类型定义了Annotation的名字、类型、成员默认值。(A定义了A的名字?这是什么语法结构?)一个Annotation类型可以说是一个特殊的java接口,它的成员变量是受限制的(......

--wocalage

2. Re:深入理解Java:注解(Annotation)基本概念

感觉读起来非常拗口,都是各种概念,而且东西太碎片化了

--wocalage

3. Re:Guava学习笔记:Guava cache

Guava库确实是好东东,但是cache模块的设计着实不敢恭维

--罗里罗嗦夫斯基

4. Re:每天一个linux命令(28):tar命令

请问能添加压缩密码么?

--fantasyxl99

5. Re:每天一个linux命令(35):ln 命令

跨文件系统是什么意思呢

--Leipfise

阅读排行榜

1. 深入理解Java:注解(Annotation)自定义注解入门(394962)

2. 每天一个linux命令(30): chown命令(392767)

3. 每天一个linux命令(7):mv命令(227911)

4. 每天一个linux命令(50):crontab命令(222221)

5. 每天一个linux命令(5):rm 命令(216455)

评论排行榜

1. 每天一个linux命令目录(47)

2. 深入理解Java:注解(Annotation)--注解处理器(45)

3. 深入理解Java:注解(Annotation)自定义注解入门(29)

4. 每天一个linux命令(1):ls命令(29)

5. 每天一个linux命令(50):crontab命令(22)

推荐排行榜

1. 每天一个linux命令目录(103)

2. 深入理解Java:注解(Annotation)自定义注解入门(75)

3. 深入理解Java:注解(Annotation)--注解处理器(59)

4. 每天一个linux命令(1):ls命令(40)

5. 每天一个linux命令(61):wget命令(36)

Copyright ©2017 peida



站长统计 站长统计
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: