Java注解Annotation原理及自定义注解代码实例

什么是注解?

对于很多初次接触的开发者来说应该都有这个疑问?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号红富士大厦

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

(0)

相关推荐

  • 5分钟搞懂java注解@Annotation的具体使用

    首先一句话结论:注解就是一种通过在类.方法.或者属性等上使用类似@xxx的方式进行"打标签",然后可以通过反射机制对标签的内容进行解析并进行相应处理的手段. 注解是java中的一个重要知识点,从java5后开始引入,尤其在spring框架中大量使用.比较常用的有@controller.@service等等各种,本文将从注解的实现原理出发,通过一些demo代码的实现,进行分析. 一. 注解定义方式 直接上代码,看看spring中@Service注解的定义就知道了: @Target({El

  • Java8新特性之重复注解(repeating annotations)浅析

    一.什么是重复注解 允许在同一申明类型(类,属性,或方法)的多次使用同一个注解 二.一个简单的例子java 8之前也有重复使用注解的解决方案,但可读性不是很好,比如下面的代码: 复制代码 代码如下: public @interface Authority {     String role();} public @interface Authorities {    Authority[] value();} public class RepeatAnnotationUseOldVersion

  • 深入理解Java注解类型(@Annotation)

    Java注解是在JDK5时引入的新特性,鉴于目前大部分框架(如spring)都使用了注解简化代码并提高编码的效率,因此掌握并深入理解注解对于一个Java工程师是来说是很有必要的事.本篇我们将通过以下几个角度来分析注解的相关知识点 理解Java注解 实际上Java注解与普通修饰符(public.static.void等)的使用方式并没有多大区别,下面的例子是常见的注解: public class AnnotationDemo { //@Test注解修饰方法A @Test public static

  • java教程之java注解annotation使用方法

    1.概述 注解可以定义到方法上,类上,一个注解相当与一个类,就相当于实例了一个对象,加上了注解,就相当于加了一个标志. 常用的注解:@Override:表示重新父类的方法,这个也可以判断是否覆盖的父类方法,在方法前面加上此语句,如果提示的错误,那么你不是覆盖的父类的方法,要是提示的没有错误,那么就是覆盖的父类的方法.@SuppressWarnings("deprecation"):取消编译器的警告(例如你使用的方法过时了)@Deprecated:在方法的最上边也上此语句,表示此方法过时

  • java 注解annotation的使用以及反射如何获取注解

     一.注解基本知识 1.元注解 元注解是指注解的注解.包括  @Retention @Target @Document @Inherited四种. 1. Annotation型定义为@interface, 所有的Annotation会自动继承java.lang.Annotation这一接口,并且不能再去继承别的类或是接口. 2. 参数成员只能用public或默认(default)这两个访问权修饰 3. 参数成员只能用基本类型byte,short,char,int,long,float,doubl

  • Java注解Annotation与自定义注解详解

    一:Java注解简介 开发中经常使用到注解,在项目中也偶尔会见到过自定义注解,今天就来探讨一下这个注解是什么鬼,以及注解的应用场景和如何自定义注解. 下面列举开发中常见的注解 @Override:用于标识该方法继承自超类, 当父类的方法被删除或修改了,编译器会提示错误信息(我们最经常看到的toString()方法上总能看到这货) @Deprecated:表示该类或者该方法已经不推荐使用,已经过期了,如果用户还是要使用,会生成编译的警告 @SuppressWarnings:用于忽略的编译器警告信息

  • 详解Java编程中Annotation注解对象的使用方法

    注解(也被称为元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据.   1.基本语法 Java SE5内置三种标准注解 @Override:表示当前的方法定义将覆盖超类中的方法.如果你不小心拼写错误,或者方法签名对不上被覆 盖的方法,编译器就会发出错误提示 @Deprecated:如果程序员使用了注解为它的元素,那么编译器就会发出警告信息 @SupperessWarnings:关闭不当的编译器警告信息. Java SE5内置四种元注解 @Targ

  • java javax.annotation.Resource注解的详解

    java 注解:java javax.annotation.Resource  当我们在xml里面为类配置注入对象时,会发现xml文件会越来越臃肿,维护起来很麻烦.这时候我们可以使用注解这种机制来为类配置注入对象. Java为我们提供了 javax.annotation.Resource这个注解. spring框架提供了org.springframework.beans.factory.annotation.Autowired. 一般情况下我们使用 javax.annotation.Resour

  • Java注解Annotation原理及自定义注解代码实例

    什么是注解? 对于很多初次接触的开发者来说应该都有这个疑问?Annontation是Java5开始引入的新特征,中文名称叫注解.它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类.方法.成员变量等)进行关联.为程序的元素(类.方法.成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用. Annontation像一种修饰符一样,应用于包.类型.构造方法.方法.成员变量.参数及本地变量的声明语句中. Java注解是

  • Java使用poi做加自定义注解实现对象与Excel相互转换

    引入依赖 maven <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.17</version> </dependency> Gradle implementation group: 'org.apache.poi', name: 'poi', version: '3.17' 代码展示 1

  • SpringBoot常见get/post请求参数处理、参数注解校验及参数自定义注解校验详解

    目录 springboot常见httpget,post请求参数处理 PathVaribale获取url路径的数据 RequestParam获取请求参数的值 注意 GET参数校验 POSTJSON参数校验 自定义注解校验 总结 spring boot 常见http get ,post请求参数处理 在定义一个Rest接口时通常会利用GET.POST.PUT.DELETE来实现数据的增删改查:这几种方式有的需要传递参数,后台开发人员必须对接收到的参数进行参数验证来确保程序的健壮性 GET一般用于查询数

  • java application maven项目打自定义zip包实例(推荐)

    1.配置pom.xml文件,添加build节点 <build> <!-- 输出的包名 --> <finalName>p2p</finalName> <sourceDirectory>src/main/java</sourceDirectory> <resources> <!-- 控制资源文件的拷贝(默认复制到classes目录,最后打进jar包) --> <resource> <directo

  • Springboot 自定义校验代码实例

    这篇文章主要介绍了Springboot 自定义校验代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 StartWithValidation.class @Documented @Constraint(validatedBy = StartWithValidator.class ) @Target({METHOD, FIELD}) @Retention(RUNTIME) public @interface StartWithValidati

  • java加密MD5实现及密码验证代码实例

    这篇文章主要介绍了java加密MD5实现及密码验证代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 MD5算法具有以下特点: 1.压缩性:任意长度的数据,算出的MD5值长度都是固定的. 2.容易计算:从原数据计算出MD5值很容易. 3.抗修改性:对原数据进行任何改动,哪怕只修改1个字节,所得到的MD5值都有很大区别. 4.强抗碰撞:已知原数据和其MD5值,想找到一个具有相同MD5值的数据(即伪造数据)是非常困难的. MD5的作用是让大容量

  • java基于poi导出excel透视表代码实例

    这篇文章主要介绍了java基于poi导出excel透视表代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 从前,我是一个前端程序猿,怀着对打通任(前)督(后)二(开)脉(发)的梦想转了后端,自学两礼拜java+spring全家桶,直接上项目实战.最近接到一需求:将业务数据导出一张透视表. 需求开发完成已近有一段时间了,甲方的大爷大妈,爷爷奶奶们也都用的很开心,我也很开心,于是就心想咱学了也不能白学,所以写下这篇随笔. 先看下用easypo

  • Java判断主机是否能ping通代码实例

    这篇文章主要介绍了Java判断主机是否能ping通代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码实现如下: import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; /** * Created by Miracle Luna on 2019/12/10 */ public class PingUtil

  • Java返回分页结果集的封装代码实例

    这篇文章主要介绍了java返回分页结果集的封装代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 代码如下 package com.leyou.common; import java.util.List; public class PageResult<T> { private long total;//总条数 private Integer totalPage;//总页数 private List<T> list; publ

  • Java Validation Api如何实现自定义注解

    背景 官方提供的注解多数可以解决现实业务场景中基本业务校验,但有些特殊场景因业务的复杂性,也还是需要在入口处对入参进行各种角度的校验,以求简化业务层的处理,降低业务处理复杂性与方法入口的强约束性. 以上背景,下面就举个简单Demo进行自定义注解校验的实现. 注解定义类 import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; impor

随机推荐