注解(Annotation)在java中应用非常广泛。它既能帮助我们在编码中减少错误,(比如最常见的Override注解),还可以帮助我们减少各种xml文件的配置,比如定义AOP切面用@AspectJ模式代替Schema模式,特别是最近接触了一点Spring MVC,每次编写Controller的时候用@RequestMapping(),@RequestParam,@ResponseBody等等。

我们所用的java中自带的注解都是定义好了的,直接拿来用,它就能发挥作用。当然了,自己也可以定义注解。

注解定义:

public @interface 注解名 {

    //…
}

可以给注解中可以定义“属性”,暂且理解为属性吧,定义如下:

public @interface MyAnnotation {

    String hello(); // 定义了一个属性名hello

    String world() default "world";// 定义了一个属性名world,默认值为“world”,注意类型匹配

    int number();// 定义了一个属性名为number

    String[] value(); // 定义了一个属性为value的数组

}

后面必须有括号,修饰符只能为public或abstract,不过一般都是默认不写的。

当我们定义一个注解时,它暗自的继承了Annotation这个借口。如果手动定义了一个Interface 并继承了java.lang.annotation.Annotation,并不意味着定义了一个注解。注解只能通过@Interface方式定义。Annotation是一个接口而不是一个注解。

使用方式:

1.当我们对一个注解定义了多个属性后,在使用该注解时,除了定义了默认值的属性,其他属性都要赋值。当然,也可以显式的对含有默认值的属性赋值。

例如:

public class MyAnnotationTest{

    private String name;
@MyAnnotation(hello = "", number = 0, value = { "aa" },world="world1")
public static void main(String[] args) {
MyAnnotationTest test = new MyAnnotationTest();
test.method();
}
@MyAnnotation(hello = "hello", number = 0, value = {"a"},world="aa")
public void method(){
System.out.println("method");
}
}

2.当一个注解只含有一个属性且属性名为value时,我们可以简化使用方式。

比如定义一个注解:
public @interface SingleAnnotation {
String[] value();
}

在使用在注解时可以简化:

    @SingleAnnotation("value")
public void singleAnnotationMethod(){ }

注解基本的定义和使用差不多就这些了。接下来看看定义的注解为什么会生效。

@Retention注解

为了更好的使用注解,java内置的这个注解也是需要了解的。

java.lang.annotation.Retention可以告诉编译器怎样去对待和处理我们自定义的注解。默认情况下会将Annotation的信息留在class文件中,但不会被JVM读取。

在使用Retention注解时,需要提供java.lang.annotation.RetentionPolicy的枚举值。编译器会根据设置不同的值来决定如何处理定义的注解。

RetentionPolicy定义如下:

public enum RetentionPolicy {

    SOURCE, //编译程序丢弃该注解,表示他不会存在于class文件中

    CLASS, //编译程序将Annotation存在class文件中(缺省)

    RUNTIME //编译程序将Annotation存在class文件中,可由JVM读取
}

比如@SuppressWarnings注解,它所对应的@Retention(RetentionPolicy.SOURCE)是这样设置的,因为它的作用是告知编译程序来压制警告,没必要将这个信息存在于class文件中。

RetentionPolicy.RUNTIME:搭配反射机制,可以让注解被JVM读出。

一个注解信息如何被JVM读出

  1.将该注解加上 @Retention(value = RetentionPolicy.RUNTIME)。

  1.获得一个类的class对象

  2.获得这个类中被该注解修饰的方法或属性。 AccessibleObject的isAnnotationPresent(Class<? extends Annotation> annotationClass)方法可以判断一个注解是否出现,由于Field和Method类继承了AccessibleObject,所以可以判断出一个类的方法或属性是否有该注解。又因为Method实现了AnnotatedElement ,所以method可以得到它对应的注解的Annotation对象,进而可以获取注解的相关信息。

下面给出例子:

首先给MyAnnotation注解 加上 @Retention(value = RetentionPolicy.RUNTIME)。

public class MyAnnotationTest{

    public static void main(String[] args)throws Exception{
MyAnnotationTest test = new MyAnnotationTest(); Class<?> clazz = test.getClass();
Method[] methods = clazz.getMethods(); for(Method m : methods){
//该方法是否出现MyAnnotation注解,出现为true,否则为false
if(m.isAnnotationPresent(MyAnnotation.class)){ MyAnnotation annotation = m.getAnnotation(MyAnnotation.class);
String hello = annotation.hello();
int number = annotation.number();
String[] values = annotation.value();
String world = annotation.world(); m.invoke(test,new Object[]{}); System.out.println("annotation.hello():" + hello);
System.out.println("annotation.number():" + number);
System.out.println("annotation.value():" + values[0]);
System.out.println("annotation.world():" + world); }
}
} @MyAnnotation(hello = "hello", number = 100, value = {"a"},world="aa")
public void method(){
System.out.println("method");
}
public void method2(){
System.out.println("method2");
} }

console 结果:

结果一目了然,可以让该方法执行,可以拿到该注解的所有赋值情况。

如果 MyAnnotation的Retention注解为 @Retention(value = RetentionPolicy.CLASS) 或@Retention(value = RetentionPolicy.SOURCE),那么method方法也不会执行,更不会获取到MyAnnotation的先关信息了。

@Target注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}

它也是用来注解我们定义的注解。value为ElementType类型的枚举值。

ElementType定义:

public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE, /** Field declaration (includes enum constants) */
FIELD, /** Method declaration */
METHOD, /** Parameter declaration */
PARAMETER, /** Constructor declaration */
CONSTRUCTOR, /** Local variable declaration */
LOCAL_VARIABLE, /** Annotation type declaration */
ANNOTATION_TYPE, /** Package declaration */
PACKAGE
}

好吧,不用解释了,看注释都知道每一个值是什么意思了。

如果一个注解被@Target直接,那么该注解所修饰的类型将受到限制,如果修饰的类型不匹配编译将会报错。

表示MyAnnotation注解只能修饰方法,可根据ElementType 的值以此类推。

@Documented

它表示被修饰的注解将会生成到javadoc帮助文档中。

@Inherited:允许子类继承父类的注解。缺省情况下子类并不会继承父类中的Annotation.

就算java的原生注解,一般也是被这几种注解中的一种或多种修饰,进而达到其功能。

总结:个其实java注解的原理还是反射。在运行时,因为有了注解,利用反射机制在运行时才会找到注解对应的方法,找到注解对应的值。值拿到了,方法也找到了,想干什么就干什么了,该干什么这一般应该是底层或框架做的事情。但我想应该就是这么回事吧!

java注解(Annotation)解析的更多相关文章

  1. Java注解全面解析(转)

    1.基本语法 注解定义看起来很像接口的定义.事实上,与其他任何接口一样,注解也将会编译成class文件. @Target(ElementType.Method) @Retention(Retentio ...

  2. Java注解(Annotation)详解

    转: Java注解(Annotation)详解 幻海流心 2018.05.23 15:20 字数 1775 阅读 380评论 0喜欢 1 Java注解(Annotation)详解 1.Annotati ...

  3. Java注解Annotation与自定义注解详解

    Java注解简介 开发中经常使用到注解,在项目中也偶尔会见到过自定义注解,今天就来探讨一下这个注解是什么鬼,以及注解的应用场景和如何自定义注解. 下面列举开发中常见的注解 @Override:用于标识 ...

  4. 深入JAVA注解-Annotation(学习过程)

    JAVA注解-Annotation学习 本文目的:项目开发过程中遇到自定义注解,想要弄清楚其原理,但是自己的基础知识不足以支撑自己去探索此问题,所以先记录问题,然后补充基础知识,然后解决其问题.记录此 ...

  5. 深入学习JAVA注解-Annotation(学习过程)

    JAVA注解-Annotation学习 本文目的:项目开发过程中遇到自定义注解,想要弄清楚其原理,但是自己的基础知识不足以支撑自己去探索此问题,所以先记录问题,然后补充基础知识,然后解决其问题.记录此 ...

  6. Java - 注解 (Annotation)

    Java - 注解 (Annotation)   一.基本的 Annotation     > 使用 Annotation 时要在其前面增加 @符号,并把该 Annotation 当成一个修饰符 ...

  7. Java注解Annotation(一)

    Java注解Annotation(一)——简介 这一章首先简单介绍一下注解,下一章会给出一个注解应用的DEMO. 1. 元注解 元注解的作用是负责注解其他的注解. JDK1.5中,定义了4个标准的me ...

  8. Java注解Annotation学习

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

  9. java注解Annotation

    扯扯注解的蛋 为什么学习注解?学习注解有什么好处?学完能做什么? 1.能够读懂别人的代码,特别是框架相关的代码 2.让编程更加简洁,代码更加清晰 3.让别人高看你一眼 注解是java1.5引入的 概念 ...

随机推荐

  1. linux下vi命令修改文件及保存的使用方法

    进入vi的命令 vi filename :打开或新建文件,并将光标置于第一行首 vi n filename :打开文件,并将光标置于第n行首 vi filename :打开文件,并将光标置于一行首 v ...

  2. LoadRunner简介

    LoadRunner是什么 LoadRunner是一个性能测试工具,它最初是Mercury公司的产品,后背HP收购. LoadRunner常用来做什么 l 验证某系统在某环境下是否满足性能需求. l  ...

  3. chart.js插件生成折线图时数据普遍较大时Y轴数据不从0开始的解决办法[bubuko.com]

    chart.js插件生成折线图时数据普遍较大时Y轴数据不从0开始的解决办法,原文:http://bubuko.com/infodetail-328671.html 默认情况下如下图 Y轴并不是从0开始 ...

  4. spring @value 注入static

    import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Com ...

  5. nodejs概要

    1.什么是Node   Node.js 可能类似jquery.js?当不是. 首先Js包含(ECMAScript 即JS- ES  BOM  DOM三类),浏览器三种都可以运行,node中只能运行EC ...

  6. 【MySQL】锁问题最佳实践

    最近一段时间处理了较多锁的问题,包括锁等待导致业务连接堆积或超时,死锁导致业务失败等,这类问题对业务可能会造成严重的影响,没有处理经验的用户往往无从下手.下面将从整个数据库设计,开发,运维阶段介绍如何 ...

  7. [asp.net]c# winform打印类

    using System; using System.Collections.Generic; using System.Text; using System.Windows.Forms; using ...

  8. DHTMLX-Vault

    DHTMLX-Vault Vault是DHTMLX中带有进度条效果的文件上传组件.该控件基于ajax文件上传功能,加入进度条图形显示每个文件的传输进程,并且可以显示预估上传时间. 基于HTML5标准, ...

  9. Zedboard安装桌面系统ubuntu及opencv(2)

    接上一篇,下面安装opencv. 一般都是参照陆佳华那本白色封皮的<软硬件协同设计>,但是不得不说这本书实在太粗糙了,很多的细节都没有说明. 首先,在PC和这块板子的方法是一样的,所以PC ...

  10. es6 class

    <!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...