本文共 4549 字,大约阅读时间需要 15 分钟。
java中我们经常要遇到各种注解,这些注解极大的方便了我们的开发。我们也就知道注解的原理好像也是一种接口和标志什么什么的,本质上说我们对JDK注解并不了解。所以理解JDK注解是我们java开发的基础。在spring中就大面积的使用了注解。所以理解这些基础的注解对于后期的开发都特别重要。
注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明。
根据注解没有没有参数可以将注解分为元数据和标记两种。
JDK自带注解
@Override 表示当前方法覆盖了父类的方法
@Deprecation 表示方法已经过时,方法上有横线,使用时会有警告。
@SuppviseWarnings 表示关闭一些警告信息(通知java编译器忽略特定的编译警告)
在实际开发中我们也需要自定义注解来实现一些功能。主要用来标记。
自定义注解声明的时候使用@interface
元注解
元注解是jdk提供给我们的基本注解,也是我们开发注解的基础。元注解有@Retention、@Target、@Document、@Inherited和@Repeatable
@Retention
是用来说明注解存在的阶段,java代码主要分为三个阶段。分别为源码、字节码和运行中。Retention就标记该注解在哪个阶段存在。
@Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含
@Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
@Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到
如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用 @Retention(RetentionPolicy.RUNTIME)
@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)作用于注解(@Retention注解中就使用该属性)
@Target(ElementType.PACKAGE) 作用于包
@Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
@Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
@Documented
用来说明是否有文档,这里的文档说的意思是通过javadoc命令生成的文档。
@Inherited
说明注解是否可以被继承
@Repeatable
用来说明注解是否可以重复修饰
注解属性类型
注解属性类型可以有以下列出的类型
1.基本数据类型
2.String
3.枚举类型
4.注解类型
5.Class类型
6.以上类型的一维数组类型
注解的属性的提取
注解的本质也是接口,对于有元数据的注解,在编译的时候会生成get方法,用来获取已经声明的值。因为我们代码的赋值操作都要经过set或者构造函数,因此对于注解来说。我们就必须通过class来检测注解和被修饰类的关系。然后通过反射获取值,然后再进行赋值操作。这样在代码运行起来的时候,我们通过注解设置的值就可以成为代码的一部分。
定义属性注解
@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)@Documented@Inheritedpublic @interface MyField { /*** * 属性 * @return */ String myName() default "默认名称";}
定义方法注解
@Inherited@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Documentedpublic @interface MyMethod { /** * value * @return */ String value() default "测试"; /** * 消息 * @return */ String message() default "测试消息";}
定义类注解
@Target(ElementType.TYPE)@Documented@Retention(RetentionPolicy.RUNTIME)@Inheritedpublic @interface MyScaffold { String value() default "类注解";}
父类
@MyScaffoldpublic class Parent { @MyMethod(value = "show",message = "测试") public void show(String name,String message){ System.out.println("调用传入的值:"+name+"---"+message); }}
子类
public class Son extends Parent{ public String test="123"; /** * 默认名称 */ @MyField(myName = "默认名称") private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Son{" + "test='" + test + '\'' + ", name='" + name + '\'' + '}'; }}
注解测试
public class TestAnnotation { /*** * 初始化一个类 */ static Parent parent=new Son(); /*** * 主函数 * @param args */ public static void main(String[] args) throws IntrospectionException, InvocationTargetException, IllegalAccessException, InstantiationException { System.out.println("原来的实体:"+parent.toString()); /*** * 代码中通过判断传入的值和注解的值 * 决定使用的值 */ showTEMP("123","123"); /*** * 类级别的注解判断 */ classTEMP(); /*** * 属性注解操作 */ fieldTEMP(); System.out.println("新的的实体:"+parent.toString()); } private static void fieldTEMP() throws IntrospectionException, InvocationTargetException, IllegalAccessException, InstantiationException { //创建一个新的son //Object obj=Son.class.newInstance(); //获取公有和私有的属性 Field[] fields = Son.class.getDeclaredFields(); for (int i=0;i0){ MyMethod annotations=list[i].getAnnotation(MyMethod.class); if (null!=annotations){ Parameter[] parameters=list[i].getParameters(); System.out.println(parameters); System.out.println("传入的值:"+s+"--"+s1); parent.show(annotations.value(),annotations.message()); System.out.println("使用注解属性值:"+annotations.value()+"--"+annotations.message()); } } } } }}
测试效果
转载地址:http://glkmi.baihongyu.com/