当前位置: 移动技术网 > IT编程>开发语言>Java > 如何自定义一个Java注解?

如何自定义一个Java注解?

2020年07月31日  | 移动技术网IT编程  | 我要评论
Java注解(Annotation)是JDK1.5引入的一种新特性,可以标注在类、方法、变量、参数上,官方定义如下:Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的一般官方定义都给的晦涩难懂,其实我们简单理解一下,注解就是标注在类、方法、变量、参数上的一种标签,你可以使用JDK内置的注解,也可以自定义注解,通常情况下我们都是使用自定义注解来完成自己的注解功能注解分为:JDK内置的注解和元注解JDK内置的注解1、@

Java注解(Annotation)是JDK1.5引入的一种新特性,可以标注在类、方法、变量、参数上,官方定义如下:

Java 注解用于为 Java 代码提供元数据。作为元数据,注解不直接影响你的代码执行,但也有一些类型的注解实际上可以用于这一目的

一般官方定义都给的晦涩难懂,其实我们简单理解一下,注解就是标注在类、方法、变量、参数上的一种标签,你可以使用JDK内置的注解,也可以自定义注解,通常情况下我们都是使用自定义注解来完成自己的注解功能

注解分为:JDK内置的注解和元注解

JDK内置的注解

1、@Override

只要学过Java面向对象特性的人对于这个注解应该都很熟悉,@Override用来标注子类覆盖父类的方法,当标注了这个注解后父类中的方法有变更,编译器会给出错误提示

2、 @Deprecated

此注解主要是用来标识一些方法已经过时了,不推荐使用了

3、@SuppressWarnings

这个注解用于告诉编译器忽略特定的警告信息,当你不希望编译器在你的方法上有警告信息时,可以通过@SuppressWarnings注解来消除警告信息

4、@SafeVarargs

Java 7 开始支持,忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告

5、@FunctionalInterface

Java 8 开始支持,标识一个匿名函数或函数式接口

使用示例

public class AnnotationTest extends HashMap { @Override public Object put(Object key, Object value) { return super.put(key, value); } @Deprecated public String testDeprecated(){ return "Deprecated"; } @SuppressWarnings("uncheck") public String testSuppressWarnings(){ return "SuppressWarnings"; } } 
public class SafeVarargsTest<T> { private T[] params; //构造函数可以使用@SafeVarargs @SafeVarargs public SafeVarargsTest(T... params){ this.params = params; } //普通方法不能使用@SafeVarargs,如果要忽略警告信息可以使用@SuppressWarnings("uncheck") //@SafeVarargs @SuppressWarnings("uncheck") public void normalMethod(T... params){ for(T t : params){ System.out.println(t); } } //static方法可以使用@SafeVarargs @SafeVarargs public static<T> void staticMethod(T... params){ for(T t : params){ System.out.println(t); } } //final方法可以使用@SafeVarargs @SafeVarargs public final void finalMethod(T... params){ for(T t : params){ System.out.println(t); } } } 
/**
 * 函数式接口:有且仅有一个抽象方法
 * @FunctionalInterface 是用来标注函数式接口的,其实不用@FunctionalInterface标注也可以表示函数式接口
 * 只是加了注解就可以从编译器的层面来限制只能包含一个抽象方法,超过一个抽象方法会报编译错误
 */ @FunctionalInterface public interface TestFunctionInterface { public void test(); //public void test1();  //会报编译错误 //Object中的方法不是抽象方法 @Override public boolean equals(Object var1); //default 不是抽象方法 public default void defaultMethod(){ } //static方法不是抽象方法 public static void staticMethod(){ } } 

元注解

元注解就是用来标记注解的注解,也就是用来自定义注解的

1、@Retention

@Retention注解用来表示注解保留的阶段(源码、字节码、运行时)

  • @Retention(RetentionPolicy.SOURCE) 注解仅存在于源码中,在class字节码文件中不包含
  • @Retention(RetentionPolicy.CLASS),默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
  • @Retention(RetentionPolicy.RUNTIME),注解会在class字节码文件中存在,在运行时可以通过反射获取到

自定义注解只能使用RetentionPolicy.RUNTIME

@Retention(RetentionPolicy.RUNTIME) public @interface FirstAnnotation { } 

2、@Target

@Target用来限定注解可以使用的范围,可以是类、方法、参数等

  • @Target(ElementType.TYPE) 作用接口、类、枚举、注解
  • @Target(ElementType.FIELD) 作用属性字段、枚举的常量
  • @Target(ElementType.METHOD) 作用方法
  • @Target(ElementType.PARAMETER) 作用方法参数
  • @Target(ElementType.CONSTRUCTOR) 作用构造函数
  • @Target(ElementType.LOCAL_VARIABLE)作用局部变量
  • @Target(ElementType.ANNOTATION_TYPE)作用于注解
  • @Target(ElementType.PACKAGE) 作用于包
  • @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型
  • @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class

一般比较常用的是ElementType.TYPE

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FirstAnnotation { } 

3、@Documented

@Documented的作用是能够将注解中的元素包含到 Javadoc 中去

4、@Inherited

当一个类被@Inherited标记时,如果子类没有被其他注解标记,那么子类会继承父类的注解

@Inherited @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FirstAnnotation { } 

5、@Repeatable

@Repeatable标记的注解表示可以同时标记一个对象多次

@Inherited @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface FirstAnnotation { RepeatAnnotionTest[] value(); } 
@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) @Repeatable(FirstAnnotation.class) public @interface RepeatAnnotionTest { String value() default ""; } 
@RepeatAnnotionTest(value = "Java") @RepeatAnnotionTest(value = "C++") @RepeatAnnotionTest(value = "Python") public class TestRepeat { } 

注解解析

上面我们介绍了元注解,也自己完成了注解的定义,但是注解只是定义出来并没有什么意义,最终我们要使用注解来帮我们完成一定的功能

这就要使用到注解解析,在Java反射中有专门用来解析注解的方法,我们可以直接使用,下面我们通过一个例子来看一下如何完成注解的解析

假如我们现在要写一个校验的注解,用来校验年龄不能低于多少岁

1、首先我们定义一个注解

@Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface ValidateAge { int minAge() default 1; } 

2、解析注解

public class TestValidateAge { public static void main(String[] args){ TestValidateAge testValidateAge = new TestValidateAge(); testValidateAge.validateAge(15); } @ValidateAge(minAge = 20) public void validateAge(int age){ System.out.println(processAnnotion(age)); } //解析注解 private String processAnnotion(int age){ try { //通过反射拿到对应的方法 Method validateAge = TestValidateAge.class.getDeclaredMethod("validateAge",int.class); //判断方法上是否存在指定的注解 boolean isPresent = validateAge.isAnnotationPresent(ValidateAge.class); if(isPresent){ //获取方法上的注解 ValidateAge annotation = validateAge.getAnnotation(ValidateAge.class); //获取注解中属性的值 int minAge = annotation.minAge(); if(age < minAge ){ return "年龄不能低于" + minAge + "岁,校验失败"; } else { return "你的年龄是" + age + "岁,校验通过"; } } } catch (NoSuchMethodException e) { e.printStackTrace(); } return "校验失败"; } } 

输出结果:

年龄不能低于20岁,校验失败 

通过上面的例子,我们完成了一个简单的校验注解,其实注解本身并不难,注解更像是我们对类、方法、参数等打一个标签,然后我通过反射来对我指定的标签进行相应的业务逻辑处理

我们常用的框架,如Spring、MyBatis都定义了自己的注解,原理都一样,都是定义一个注解,然后复用注解解析器来对指定的注解进行不同的业务处理

明白了这其中的原理,我们就可以自定义一些注解来完成我们的业务处理

本文地址:https://blog.csdn.net/pzjtian/article/details/107678197

如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!

相关文章:

验证码:
移动技术网