Java注解使用及原理解析

基本特性

1、jdk 1.5之后才引入的。

2、用来说明程序的。(注释是给程序员看的,注解就是给电脑看的)

java注解的作用分类

1、编写文档:通过代码标识的注解生成文档。【生成doc文档】

2、代码分析:通过代码标识的注解对代码进行分析。【使用反射】

3、编译检查:通过代码标识的注解让编译器能够实现基本的编译检查。【override】

测试类:

/**
 * 我的javadoc测试
 */
public class TestCode {
  /**
   * 计算两个数的和
   * @param a 整数a
   * @param b 整数b
   * @return 返回两个数的和
   */
  public int add(int a, int b){
    return a+b;
  }
}

对于2、3两点我们应该是知道的。尽管可能不知道里面的原理。但是是平时都在用的。但是对于1点还可以生成doc文档?

测试操作如下:

D:\soft\jdk\bin\javadoc.exe .\TestCode.java -encoding utf-8 -docEncoding utf-8 -charset utf-8

生成了一大堆的东西:

打开TestCode.html可以发现,我们的java api手册就是这样生产的。

注解来源分类

1、jdk自带的注解,如常见的override(重写校验),deprecated(表示弃用)

2、自定义的注解

1)格式, 以override为例:

2)注解的本质

我们编写一个简单的注解

MyAnnotation.java

public @interface MyAnnotation {}

我们通过编译和反编译看下最终是什么样的结果:

D:\soft\jdk\bin\javac.exe MyAnnotation.java

D:\soft\jdk\bin\javap.exe MyAnnotation.class

结果如下:

public interface MyAnnotation extends java.lang.annotation.Annotation {

}

可以发现注解的本质就是接口,这个接口继承了jdk里面的Annotation接口。

3)注解的属性

由于注解本质为接口,那么里面可以定义未实现的方法。这些称为注解的“属性”。

属性的返回类型有(返回值不能为void):

  • 基本数据类型
  • String
  • 枚举
  • 注解
  • 以及以上四种类型的数组

例子:

public enum Person {
  PS;
}
public @interface Annotation2 {
}
public @interface MyAnnotation {
  String stringValue();
  int integerValue();
  Person personValue();
  Annotation2 myAnnotationValue();
  String[] stringArrayValue();
}

属性的使用,需要注意几点:

  • 定义了属性在使用的时候就要给属性赋值,除非设置default值。如:String stringValue() default "aaa";
  • 如果属性为value且属性只有这一个,那么value可以省略,直接填写属性值。
  • 如果是数组,需要用{}包含起来。
public @interface MyAnnotation {
  String stringValue() default "xxx";
  int integerValue();
  String[] stringArrayValue();
}

public @interface Annotation2 {
  String value();
}

@MyAnnotation(integerValue = 1, stringArrayValue = {"aaa", "bbb"})
@Annotation2("default")
public class TestCode {
  /**
   * 计算两个数的和
   * @param a 整数a
   * @param b 整数b
   * @return 返回两个数的和
   */
  public int add(int a, int b){
    return a+b;
  }

  @Override
  public String toString() {
    return super.toString();
  }
}

元注解

元注解是你在编写注解的时候,上面加的注解,就是注解的注解。主要有4个。

  • @target, 用于指定注解的使用位置。如@Target(ElementType.ANNOTATION_TYPE),@Target(value = {ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})。
  • @Inherited,表示父类加了这个注解,子类也自动加上。
  • @Documented, 表示这个注解的信息在执行javadoc的时候是否抽取到api文档中。
  • @Retention,表示注解被保留的阶段,java类,class文件,以及被jvm读取。总共三种。RetentionPolicy.SOURCE, RetentionPolicy.CLASS, RetentionPolicy.RUNTIME

元注解的内容,可以到jdk源码里面看一下,更有利于理解。

解析注解

这个是最关键了,以上加了这么多的属性,并且还为这些属性附了值,那么是希望程序读取这些值,进行使用的。那其实就是要看如何拿到这些注解配置的值。

测试:

MyAnnotition.java:

package annotation_;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
  String stringValue() default "xxx";
  int integerValue();
}

TestCode.java:

package annotation_;
@MyAnnotation(integerValue = 1)
public class TestCode {
  public static void main(String[] args) {
    Class<TestCode> testCodeClass = TestCode.class;
    MyAnnotation myAnnotation = testCodeClass.getAnnotation(MyAnnotation.class);
    int i = myAnnotation.integerValue();
    String s = myAnnotation.stringValue();
    System.out.printf("i = %d, s = %s\n", i, s);
  }
}

输出结果:

Connected to the target VM, address: '127.0.0.1:49586', transport: 'socket'
i = 1, s = xxx
Disconnected from the target VM, address: '127.0.0.1:49586', transport: 'socket'

Process finished with exit code 0

是不是感觉可以当配置文件使用。但是最主要的问题是myAnnotation.integerValue(),myAnnotation.stringValue()为什么可以拿到对应的值,这个也是最核心的问题。

那就是getAnnotation里面返回了一个实现了MyAnnotation注解(注解的本质是接口)的实例。这个类大概是长这样的。

package annotation_;

import java.lang.annotation.Annotation;

public class MyAnnotationImpl implements MyAnnotation{
  public String stringValue() {
    return "xxx";
  }
  public int integerValue() {
    return 0;
  }
  public Class<? extends Annotation> annotationType() {
    return null;
  }
}

所以就可以通过抽象方法获取到对应的值。(如何生成这样的一个类,只是学习注解,可以不关心。要不然,只能看里面的源码。因为如果自定义注解,你只会用到这一步,去获取值。)

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • java中注解机制及其原理的详解

    java中注解机制及其原理的详解 什么是注解 注解也叫元数据,例如我们常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包.类.接口.字段.方法参数.局部变量等进行注解.它主要的作用有以下四方面: 生成文档,通过代码里标识的元数据生成javadoc文档. 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证. 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码. 运行时动态处理,运行时通过代码里标识

  • Java注解与反射原理说明

    一 点睛 注解若想发挥更大作用,还需借助反射机制之力.通过反射,可以取得一个方法上声明的注解的全部内容. 一般有两种需求: 1 取得方法中全部的注解,通过调用getAnnotations来实现. 2 判断操作是否是指定注解,通过调用getAnnotation来实现. 下面从源码角度来说明怎样获取这些注解信息. 二 源码导读--取得方法中全部的注解 public class AccessibleObject implements AnnotatedElement { ... //取得全部Annot

  • Java 什么是注解及注解原理详细介绍

    Java 注解的原理 java : 注解使用,http://www.jb51.net/article/101747.htm 什么是注解 注解也叫元数据,例如我们常见的@Override和@Deprecated,注解是JDK1.5版本开始引入的一个特性,用于对代码进行说明,可以对包.类.接口.字段.方法参数.局部变量等进行注解.它主要的作用有以下四方面: 生成文档,通过代码里标识的元数据生成javadoc文档. 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证. 编译时动态处理,编译

  • java元注解@Inherited的使用详解

    1.先看源码文档 /** * Indicates that an annotation type is automatically inherited. If * an Inherited meta-annotation is present on an annotation type * declaration, and the user queries the annotation type on a class * declaration, and the class declaratio

  • Java中注解的工作原理

    自Java5.0版本引入注解之后,它就成为了Java平台中非常重要的一部分.开发过程中,我们也时常在应用代码中会看到诸如@Override,@Deprecated这样的注解.这篇文章中,我将向大家讲述到底什么是注解,为什么要引入注解,注解是如何工作的,如何编写自定义的注解(通过例子),什么情况下可以使用注解以及最新注解和ADF(应用开发框架).这会花点儿时间,所以为自己准备一杯咖啡,让我们来进入注解的世界吧. 什么是注解? 用一个词就可以描述注解,那就是元数据,即一种描述数据的数据.所以,可以说

  • Java注解机制之Spring自动装配实现原理详解

    Java中使用注解的情况主要在SpringMVC(Spring Boot等),注解实际上相当于一种标记语言,它允许你在运行时动态地对拥有该标记的成员进行操作.注意:spring框架默认不支持自动装配的,要想使用自动装配需要修改spring配置文件中<bean>标签的autowire属性. 自动装配属性有6个值可选,分别代表不同的含义: byName ->从Spring环境中获取目标对象时,目标对象中的属性会根据名称在整个Spring环境中查找<bean>标签的id属性值.如果

  • Java8接口默认静态方法及重复注解原理解析

    接口默认方法和静态方法 默认方法 interface MyInterface1 { default String method1() { return "myInterface1 default method"; } } class MyClass{ public String method1() { return "myClass method"; } } /** * 父类和接口中都有相同的方法,默认使用父类的方法,即类优先 * @author 莫雨朵 * */

  • Java使用@Validated注解进行参数验证的方法

    目前项目中大部分代码进行参数验证都是写代码进行验证,为了提升方便性和代码的简洁性,所以整理了下使用注解进行参数验证.使用效果如下: // 要验证的实体类 @Data public class User implements Serializable { @NotBlank(message = "id不能为空!",groups = Update.class) protected String id = ""; @NotBlank(message = "商户i

  • Java注解使用及原理解析

    基本特性 1.jdk 1.5之后才引入的. 2.用来说明程序的.(注释是给程序员看的,注解就是给电脑看的) java注解的作用分类 1.编写文档:通过代码标识的注解生成文档.[生成doc文档] 2.代码分析:通过代码标识的注解对代码进行分析.[使用反射] 3.编译检查:通过代码标识的注解让编译器能够实现基本的编译检查.[override] 测试类: /** * 我的javadoc测试 */ public class TestCode { /** * 计算两个数的和 * @param a 整数a

  • Java设计模式模板方法(Template)原理解析

    这篇文章主要介绍了Java设计模式模板方法(Template)原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 前言: 我们在开发中有很多固定的流程,这些流程有很多步凑是固定的,比如JDBC中获取连接,关闭连接这些流程是固定不变的,变动的只有设置参数,解析结果集这些是根据不同的实体对象"来做调整",针对这种拥有固定算法流程,其中有固定的步凑,存在不固定的步凑的情况下就诞生了模板方法模式. 模板方法模式(Template)定义:

  • Java实现顺序栈原理解析

    这篇文章主要介绍了Java实现顺序栈原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 什么是栈 1.栈的英文是stack 2.栈是一个先入后出的有序列表 3.栈是限制线性表元素的插入和删除只能在线性表的同一端进行的一种特殊的线性表,允许插入和删除的一端是,为变化的一端,成为栈顶,另外的一端为固定的一端为栈底 4.栈的定义可知,最先放入栈中的元素在栈底,最后放入的元素在栈顶,而删除的情况刚好相反,最后放入的元素先删除,最先放入的元素后删除

  • Java方法参数传递机制原理解析

    这篇文章主要介绍了Java方法参数传递机制原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Java方法中如果声明了形参,在调用方法时就必须给这些形参指定参数值,实际传进去的这个值就叫做实参. 这就涉及到Java中的参数传递机制,值传递. 基本数据类型 基本数据类型,值传递的体现是数值的传递. public class TransferTempTest { public static void main(String[] args) {

  • Java线程状态运行原理解析

    这篇文章主要介绍了Java线程状态运行原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码实例如下 package com.fgy.demo05; /** * 等待唤醒案例:线程之间通信 * 注意: * 同步使用的锁对象必须唯一 * 只有锁对象才能调用wait和notify()/notifyAll()方法 */ public class Demo1WaitAndNotify { public static void main(Strin

  • Java switch case数据类型原理解析

    这篇文章主要介绍了Java switch case数据类型原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Java 中 switch case 语句用来判断一个变量与一系列值中某个值是否相等,每个值称为一个分支. 语法格式如下: switch(expression){ case value : //语句 break; //可选 case value : //语句 break; //可选 //你可以有任意数量的case语句 default

  • Java多态中动态绑定原理解析

    这篇文章主要介绍了Java多态中动态绑定原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 多态是面向对象程序设计非常重要的特性,它让程序拥有 更好的可读性和可扩展性. 发生在继承关系中. 需要子类重写父类的方法. 父类类型的引用指向子类类型的对象. 自始至终,多态都是对于方法而言,对于类中的成员变量,没有多态的说法. 一个基类的引用变量接收不同子类的对象将会调用子类对应的方法,这其实就是动态绑定的过程.在理解动态绑定之前,先补充一些概念.

  • Java并发CopyOnWrite容器原理解析

    这篇文章主要介绍了Java并发CopyOnWrite容器原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 Copy-On-Write简称COW,是一种用于程序设计中的优化策略.其基本思路是,从一开始大家都在共享同一个内容,当某个人想要修改这个内容的时候,才会真正把内容Copy出去形成一个新的内容然后再改,这是一种延时懒惰策略.从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器,它们是CopyOnWri

  • java中fork-join的原理解析

    ForkJoinTask就是ForkJoinPool里面的每一个任务.他主要有两个子类:RecursiveAction和RecursiveTask.然后通过fork()方法去分配任务执行任务,通过join()方法汇总任务结果, 这就是整个过程的运用.他有两个子类,使用这两个子类都可以实现我们的任务分配和计算. (1)RecursiveAction 一个递归无结果的ForkJoinTask(没有返回值) (2)RecursiveTask 一个递归有结果的ForkJoinTask(有返回值) For

  • GC参考手册二java中垃圾回收原理解析

    内存碎片整理 每次执行清除(sweeping), JVM 都必须保证不可达对象占用的内存能被回收重用.但这(最终)有可能会产生内存碎片(类似于磁盘碎片), 进而引发两个问题: 写入操作越来越耗时, 因为寻找一块足够大的空闲内存会变得非常麻烦. 在创建新对象时, JVM在连续的块中分配内存.如果碎片问题很严重, 直至没有空闲片段能存放下新创建的对象,就会发生内存分配错误(allocation error). 要避免这类问题,JVM 必须确保碎片问题不失控.因此在垃圾收集过程中, 不仅仅是标记和清除

随机推荐