什么是注解?

对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解。它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
  Java注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。

注解的用处:

1、生成文档。这是最常见的,也是java 最早提供的注解。常用的有@param @return 等
      2、跟踪代码依赖性,实现替代配置文件功能。比如Dagger 2 依赖注入,未来java 开发,将大量注解配置,具有很大用处;
      3、在编译时进行格式检查。如@override 放在方法前,如果你这个方法并不是覆盖了超类方法,则编译时就能检查出。

注解的原理:

  注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandler 的invoke 方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。

元注解:

java.lang.annotation 提供了四种元注解,专门注解其他的注解(在自定义注解的时候,需要使用到元注解):
   @Documented – 注解是否将包含在JavaDoc中
   @Retention – 什么时候使用该注解
   @Target – 注解用于什么地方
   @Inherited – 是否允许子类继承该注解

1.)@Retention – 定义该注解的生命周期
  ●   RetentionPolicy.SOURCE : 在编译阶段丢弃。这些注解在编译结束之后就不再有任何意义,所以它们不会写入字节码。@Override, @SuppressWarnings都属于这类注解。
  ●   RetentionPolicy.CLASS : 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式
  ●   RetentionPolicy.RUNTIME : 始终不会丢弃,运行期也保留该注解,因此可以使用反射机制读取该注解的信息。我们自定义的注解通常使用这种方式。

2.)Target – 表示该注解用于什么地方。默认值为任何元素,表示该注解用于什么地方。可用的ElementType 参数包括
  ● ElementType.CONSTRUCTOR: 用于描述构造器
  ● ElementType.FIELD: 成员变量、对象、属性(包括enum实例)
  ● ElementType.LOCAL_VARIABLE: 用于描述局部变量
  ● ElementType.METHOD: 用于描述方法
  ● ElementType.PACKAGE: 用于描述包
  ● ElementType.PARAMETER: 用于描述参数
  ● ElementType.TYPE: 用于描述类、接口(包括注解类型) 或enum声明

3.)@Documented – 一个简单的Annotations 标记注解,表示是否将注解信息添加在java 文档中。

4.)@Inherited – 定义该注释和子类的关系
     @Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited 修饰的annotation 类型被用于一个class,则这个annotation 将被用于该class 的子类。

常见标准的Annotation:

1.)Override
      java.lang.Override 是一个标记类型注解,它被用作标注方法。它说明了被标注的方法重写了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时,java 编译器将以一个编译错误来警示。
  2.)Deprecated
     Deprecated 也是一种标记类型注解。当一个类型或者类型成员使用@Deprecated 修饰的话,编译器将不鼓励使用这个被标注的程序元素。所以使用这种修饰具有一定的“延续性”:如果我们在代码中通过继承或者覆盖的方式使用了这个过时的类型或者成员,虽然继承或者覆盖后的类型或者成员并不是被声明为@Deprecated,但编译器仍然要报警。
 3.)SuppressWarnings
     SuppressWarning 不是一个标记类型注解。它有一个类型为String[] 的成员,这个成员的值为被禁止的警告名。对于javac 编译器来讲,被-Xlint 选项有效的警告名也同样对@SuppressWarings 有效,同时编译器忽略掉无法识别的警告名。
  @SuppressWarnings("unchecked")

自定义注解:

自定义注解类编写的一些规则:
  1. Annotation 型定义为@interface, 所有的Annotation 会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口.
  2. 参数成员只能用public 或默认(default) 这两个访问权修饰
  3. 参数成员只能用基本类型byte、short、char、int、long、float、double、boolean八种基本数据类型和String、Enum、Class、annotations等数据类型,以及这一些类型的数组.
  4. 要获取类方法和字段的注解信息,必须通过Java的反射技术来获取 Annotation 对象,因为你除此之外没有别的获取注解对象的方法
  5. 注解也可以没有定义成员,,不过这样注解就没啥用了
PS:自定义注解需要使用到元注解

自定义注解实例:

FruitName.java

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

FruitColor.java

 import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; /**
* 水果颜色注解
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitColor {
/**
* 颜色枚举
*/
public enum Color{ BLUE,RED,GREEN}; /**
* 颜色属性
*/
Color fruitColor() default Color.GREEN; }

FruitProvider.java

 import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.RetentionPolicy.RUNTIME; /**
* 水果供应者注解
*/
@Target(FIELD)
@Retention(RUNTIME)
@Documented
public @interface FruitProvider {
/**
* 供应商编号
*/
public int id() default -1; /**
* 供应商名称
*/
public String name() default ""; /**
* 供应商地址
*/
public String address() default "";
}

FruitInfoUtil.java

 import java.lang.reflect.Field;

 /**
* 注解处理器
*/
public class FruitInfoUtil {
public static void getFruitInfo(Class<?> clazz){ String strFruitName=" 水果名称:";
String strFruitColor=" 水果颜色:";
String strFruitProvicer="供应商信息:"; Field[] fields = clazz.getDeclaredFields(); for(Field field :fields){
if(field.isAnnotationPresent(FruitName.class)){
FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);
strFruitName=strFruitName+fruitName.value();
System.out.println(strFruitName);
}
else if(field.isAnnotationPresent(FruitColor.class)){
FruitColor fruitColor= (FruitColor) field.getAnnotation(FruitColor.class);
strFruitColor=strFruitColor+fruitColor.fruitColor().toString();
System.out.println(strFruitColor);
}
else if(field.isAnnotationPresent(FruitProvider.class)){
FruitProvider fruitProvider= (FruitProvider) field.getAnnotation(FruitProvider.class);
strFruitProvicer=" 供应商编号:"+fruitProvider.id()+" 供应商名称:"+fruitProvider.name()+" 供应商地址:"+fruitProvider.address();
System.out.println(strFruitProvicer);
}
}
}
}

Apple.java

 import test.FruitColor.Color;

 /**
* 注解使用
*/
public class Apple { @FruitName("Apple")
private String appleName; @FruitColor(fruitColor=Color.RED)
private String appleColor; @FruitProvider(id=1,name="陕西红富士集团",address="陕西省西安市延安路89号红富士大厦")
private String appleProvider; 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 setAppleProvider(String appleProvider) {
this.appleProvider = appleProvider;
}
public String getAppleProvider() {
return appleProvider;
} public void displayName(){
System.out.println("水果的名字是:苹果");
}
}

FruitRun.java

 /**
* 输出结果
*/
public class FruitRun {
public static void main(String[] args) {
FruitInfoUtil.getFruitInfo(Apple.class);
}
}

运行结果是:

水果名称:Apple
 水果颜色:RED
 供应商编号:1 供应商名称:陕西红富士集团 供应商地址:陕西省西安市延安路89号红富士大厦

参考链接:
[1]http://www.cnblogs.com/peida/archive/2013/04/26/3038503.html
[2]http://www.cnblogs.com/whoislcj/p/5671622.html
[3]http://blog.csdn.net/lylwo317/article/details/52163304

注解Annotation实现原理与自定义注解例子的更多相关文章

  1. Java基础笔记 – Annotation注解的介绍和使用 自定义注解

    Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 |  被围观 25,969 views+ 1.Anno ...

  2. Java学习之注解Annotation实现原理

    前言: 最近学习了EventBus.BufferKinfe.GreenDao.Retrofit 等优秀开源框架,它们新版本无一另外的都使用到了注解的方式,我们使用在使用的时候也尝到不少好处,基于这种想 ...

  3. 自定义注解_格式&本质和自定义注解_属性定义

    自定义注解: 格式: public @interface 注解名称{} 本质:注解本质上就是一个接口,该接口默认继承Annotation接口 public interface MyAnno exten ...

  4. Spring框架context的注解管理方法之二 使用注解注入基本类型和对象属性 注解annotation和配置文件混合使用(半注解)

    首先还是xml的配置文件 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns=" ...

  5. 使用Java反射(Reflect)、自定义注解(Customer Annotation)生成简单SQL语句

    这次给大家介绍一下在Java开发过程中 使用自定义注解开发:主要知识点:            1.反射            主要用于提取注解信息            2.自定义异常  主要是为了 ...

  6. springboot Aop配置,并使用自定义注解annotation,并且拦截service层

    前言 用Spring Boot的AOP来简化处理自定义注解,并将通过实现一个简单的方法执行判断节点是否开始的状态示列源码. AOP概念 面向侧面的程序设计(aspect-oriented progra ...

  7. java注解和自定义注解的简单使用

    前言 在使用Spring Boot的时候,大量使用注解的语法去替代XML配置文件,十分好用. 然而,在使用注解的时候只知道使用,却不知道原理.直到需要用到自定义注解的时候,才发现对注解原理一无所知,所 ...

  8. Java自定义注解和运行时靠反射获取注解

    转载:http://blog.csdn.net/bao19901210/article/details/17201173/ java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编 ...

  9. Java注解Annotation学习

    学习注解Annotation的原理,这篇讲的不错:http://blog.csdn.net/lylwo317/article/details/52163304 先自定义一个运行时注解 @Target( ...

随机推荐

  1. 1207. [HNOI2004]打鼹鼠【线性DP】

    Description 鼹鼠是一种很喜欢挖洞的动物,但每过一定的时间,它还是喜欢把头探出到地面上来透透气的.根据这个特点阿Q编写了一个打鼹鼠的游戏:在一个n*n的网格中,在某些时刻鼹鼠会在某一个网格探 ...

  2. day4-课堂代码

    # ---------------------------------------------------------------------- # def my_function1(name, ad ...

  3. jenkins报错;自定义工作目录;

    [1]no such file 报错: 如果jdk配置路径错误,有可能会报这样的错误: 其实只要在/etc/profile中配置好JAVA_HOME就足够了: 对应的系统配置框,留空不新加即可: [2 ...

  4. git reset之后找回本地未提交的代码

    头脑发热使用了git reset命令回退到了之前的一个版本,结果把本地没有提交的代码给覆盖掉了..... 作为一个bug员自然是想恢复,毕竟重新写还得再测一遍,本着能懒一点是一点的原则,开始了恢复代码 ...

  5. boot.img的修改

    个文件:boot.img.system.img.userdata.img.其中boot.img 存放着内核以及Android系统的配置信息,比如android系统各文件夹的读写权限,adb 的权限.所 ...

  6. 20155222卢梓杰 实验五 MSF基础应用

    实验五 MSF基础应用 1.一个主动攻击实践,如ms17_010_eternalblue漏洞; 本次攻击目标是win7虚拟机 首先进行相应配置 然后点launch 就成功了 针对win7的漏洞还是相对 ...

  7. git 认识

    GIT (分布式版本控制系统) <百度文库>Git是一款免费.开源的分布式版本控制系统,用于敏捷高效地处理任何或小或大的项目.<百度文库>                   ...

  8. EZ 2018 03 16 NOIP2018 模拟赛(四)

    链接:http://211.140.156.254:2333/contest/64 我去掉了一百多分! 这次的题目怎么说呢,特别水,但是就是出现了一些很逗的错误导致炸裂. 最好笑的是SB的不只我一个: ...

  9. [Oracle]OpenVMS 运行 Oracle 时的推荐值

    PQL Parameters            ORACLE Account  ------------------        -------------------------  PQL_M ...

  10. [清华集训2015 Day2]矩阵变换-[稳定婚姻模型]

    Description 给出一个N行M列的矩阵,保证满足以下性质: M>N. 矩阵中每个数都是 [0,N]中的自然数. 每行中, [1,N]中每个自然数刚好出现一次,其余的都是0. 每列中,[1 ...