java注解Annotation怎么玩?

refer:来自:https://www.cnblogs.com/acm-bingzi/p/javaAnnotation.html


系列文章目录


1 什么是注解?

Java5之后可以在源代码中嵌入一些补充信息,这种补充信息称为注解(Annotation)。
例如在方法覆 盖中使用过的@Override注解,注解都是@符号开头的。

注解并不能改变程序运行的结果,不会影响程序运行的性能。有些注解可以在编译时给用户提示或警 告,有的注解可以在运行时读写字节码文件信息。

2 注解的原理:

注解本质都是一种 数据类型,是接口类型,你创建一个注解类源文件,实际上等价于==创建了一个继承了Annotation接口的特殊接口。

3 注解分类——基本注解

到Java 8为止Java SE提供11种内置注解。

其中有5是基本注解,它们来自于java.lang包。
基本注解包括:@Override、@Deprecated、@SuppressWarnings、@SafeVarargs和 @FunctionalInterface。

其余6个是元注解(Meta Annotation),它们来自于 java.lang.annotation包,自定义注解时 会用到元注解。
元注解用来 注解其他的注解。

4 注解分类——元注解

元注解包括:@Documented@Target@Retention@Inherited@Repeatable@Native

元注解是 为其他注解进行说明的注解,当自定义一个新的注解类型时,其中可以使用元注解。

常用的自定义注解如下:

  • @Documented:javadoc等工具可以提取这些注解信息
  • @Target用来指定 新注解的适用位置。@Target注解有一个成员(value)用来设置适用 位置,value是 java.lang.annotation.ElementType枚举类型的数组,ElementType描述Java程序元素 类型,它有10个枚举常量,如下:在这里插入图片描述
  • @Retention:@Retention注解用来指定一个新注解的有效范围,@Retention注解有一个成员(value)用来设 置保留策略,value是java.lang.annotation.RetentionPolicy枚举类型,RetentionPolicy描述注解保留 策略,它有3个枚举常量,如下所示:在这里插入图片描述
    元注解还有如下:在这里插入图片描述

4 自定义注解使用

4.1 声明一个基本注解

声明自定义注解可以使用@interface 关键字实现,最简单形式的注解示例代码如下:

// Marker.java文件 
package com.a51work6; 

public @interface Marker{
}

上述代码声明一个Marker注解,@interface声明一个注解类型。
Marker注解中不包含任何的成员,这种注解称为标记注解,基本注解中的@Override就属于标记注解。

根据需要注解中可以包含一些成员,和成员的默认值,示例代码如下:

//Marker.java文件
package com.a51work6; 

//带有默认值注解 
@interface MyAnnotation1 { 
	String value() default "注解信息";
	int count() default 0; 
}

使用此注解如下:

//HelloWorld.java文件 
package com.a51work6; 

@Marker
public class HelloWorld { 
	@MyAnnotation(value = "Annotation") 
	private String info = ""; 
	@MyAnnotation1(count = 10) 
	public static void main(String[] args) {
		
	} 
}

默认情况下注解可以修饰任意的程序元素(类、接口、成员变量、成员方法和数据类型等)。

  • 代码第 ①行使用@Marker注解修饰类。
  • 代码第②行是@MyAnnotation(value = “Annotation”)注解修饰成员变 量,其中value = "Annotation"是为value成员提供数值。
  • 代码第③行是@MyAnnotation1(count = 10) 注解 修饰成员方法,@MyAnnotation1有两个成员,但是只为count成员赋值,另外一个成员value使用默认 值。

4.2 使用元注解声明新注解

上面4.1 声明注解只是最基本形式的注解,对于复杂的注解可以在声明注解时使用元注解。下面通过一 个案例介绍一下在自定义注解中使用元注解.

首先看看第一个注解MyAnnotation,它用来修饰类或接口,MyAnnotation代码如下:

//MyAnnotation.java文件

package com.a51work6;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Documented;
import java.lang.annotation.Target;

@Documented                               //1
@Target({ElementType.TYPE})               //2
@Retention(RetentionPolicy.RUNTIME)       //3
public @interface MyAnnotation {          //4

    String description();                 //5
}

其中使用了三个元注解修饰MyAnnotation注解,

  • 代码 第①行使用@Documented指定MyAnnotation注解信息可以被javadoc工具读取。
  • 代码第②行使用 @Target({ ElementType.TYPE })指定MyAnnotation注解用于修饰类和接口等类型
  • 代码第③行 @Retention(RetentionPolicy.RUNTIME)指定MyAnnotation注解信息可以在运行时被读取。
  • 代码第⑤行 的description是MyAnnotation注解的成员。

第二个注解MemberAnnotation,它用来类中成员变量和成员方法,MemberAnnotation代码如下:
//MemberAnnotation.java文件

package com.a51work6;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented @Retention(RetentionPolicy.RUNTIME)@Target({ElementType.FIELD, ElementType.METHOD})public @interface MemberAnnotation { ③

    Class<?> type() default void.class; ④

    String description();}

使用了MyAnnotation和MemberAnnotation注解是Person类,Person类代码如下:

Person.java文件

package com.a51work6;

@MyAnnotation(description = "这是一个测试类")public class Person {
    @MemberAnnotation(type = String.class, description = "名字")private String name;
    @MemberAnnotation(type = int.class, description = "年龄")private int age;
    @MemberAnnotation(type = String.class, description = "获得名字")public String getName() {
        return name;
    }

    @MemberAnnotation(type = int.class, description = "获得年龄")public int getAge() {
        return age;
    }

    @MemberAnnotation(description = "设置姓名和年龄")public void setNameAndAge(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

读取运行时注解信息:
注解是为工具读取信息而准备的。有些工具可以读取源代码文件中的注解信息;有的可以读取字节码 文件中的注解信息;有的可以在运行时读取注解信息。但是读取这些注解信息的代码都是一样的,区 别只在于自定义注解中@Retention的保留策略不同。

读取注解信息需要反射相关API,Class类如下方法:

  • A getAnnotation(Class annotationClass):如果此元素存在 annotationClass类型的注解,则返回注解,否则返回null。
  • Annotation[] getAnnotations():返回此元素上存在的所有注解。
  • Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注解。与getAnnotations() 区别在于该方法将不返回继承的注释。
  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):如果此元素上存在 annotationClass类型的注解,则返回true,否则返回false。
  • boolean isAnnotation():如果此Class对象表示一个注解类型则返回true。

运行时Person类中注解信息代码如下:
//HelloWorld.java文件


package com.a51work6;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class HelloWorld {
    public static void main(String[] args) {
        try {
            Class<?> clz = Class.forName("com.a51work6.Person");  // 读取类注解
            if (clz.isAnnotationPresent(MyAnnotation.class)) {
                MyAnnotation ann = (MyAnnotation) clz.getAnnotation(MyAnnotation.class);
                System.out.printf("类%s,读取注解描述: %s \n", clz.getName(), ann.description());
            }// 读取成员方法的注解信息
            Method[] methods = clz.getDeclaredMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(MemberAnnotation.class)) {
                    MemberAnnotation ann = method.getAnnotation(MemberAnnotation.class);
                    System.out.printf("方法%s,读取注解描述: %s \n", method.getName(), ann.description());
                }
            }// 读取成员变量的注解信息
            Field[] fields = clz.getDeclaredFields();
            for (Field field : fields) {
                if (field.isAnnotationPresent(MemberAnnotation.class)) {
                    MemberAnnotation ann = field.getAnnotation(MemberAnnotation.class);
                    System.out.printf("成员变量%s,读取注解描述: %s \n", field.getName(), ann.description());
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

上述代码第①行是创建Person类对应的Class对象,代码第②行是判断Person类是否存在MyAnnotation注 解,如果存在则通过代码第③行的getAnnotation方法将MyAnnotation注解实例返回。代码第④行中 ann.description()表达式读取MyAnnotation注解中description成员内容。

代码第⑤行是获得所有成员方法对象数组,通过遍历方法对象数组,在代码第⑥行判断方法中是否存 在MemberAnnotation注解,如果存在则通过代码第⑦行的getAnnotation方法将MemberAnnotation注解实 例返回。代码第⑧行中ann.description()表达式读取MemberAnnotation注解中description成员内容。

代码第⑨行是获得所有成员变量对象数组,代码第⑩行是判断成员变量中是否存在MemberAnnotation 注解。其他的处理与成员方法类似,这里不再赘述。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值