Annotation的学习

本文深入讲解Java注解的概念、原理及其应用场合,并通过实例演示如何自定义注解及利用反射机制实现注解的功能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、概念:     
     Annotation它提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。更通俗的意思是为程序的元素(类、方法、成员变量)加上更直观更明了的说明,这些说明信息是与程序的业务逻辑无关,并且是供指定的工具或框架使用的。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。

二、原理:
     Annotation其实是一种接口。通过Java的反射机制相关的API来访问annotation信息。 相关类(框架或工具中的类)根据这些信息来决定如何使用该程序元素或改变它们的行为。annotation是不会影响程序代码的执行,无论annotation怎么变化,代码都始终如一地执行。annotation是不会影响程序代码的执行,无论annotation怎么变化,代码都始终如一地执行。
     Annotationinterface的异同
1)、Annotation类型使用关键字@interface而不是interface
2)、Annotation类型、方法定义是独特的、受限制的。
     Annotation 类型的方法必须声明为无参数、无异常抛出的。这些方法定义了annotation的成员:方法名成为了成员名,而方法返回值成为了成员的类型。而方法返回值类型必须为primitive类型、Class类型、枚举类型、annotation类型或者由前面类型之一作为元素的一维数组。方法的后面可以使用 default和一个默认数值来声明成员的默认值,null不能作为成员默认值,这与我们在非annotation类型中定义方法有很大不同。
     Annotation类型和它的方法不能使用annotation类型的参数、成员不能是generic。只有返回值类型是Class的方法可以在annotation类型中使用generic,因为此方法能够用类转换将各种类型转换为Class
3)、Annotation类型又与接口有着近似之处。
     它们可以定义常量、静态成员类型(比如枚举类型定义)。Annotation类型也可以如接口一般被实现或者继承。

三、应用场合
     annotation一般作为一种辅助途径,应用在软件框架或工具中,在这些工具类中根据不同的 annontation注解信息采取不同的处理过程或改变相应程序元素(类、方法及成员变量等)的行为。
     例如:JunitStrutsSpring等流行工具框架中均广泛使用了annontion。使代码的灵活性大提高。

四、基本语法:
Java目前包括三种标准注解和四种元注解。元注解主要负责注解其他注解的。
三种标准注解:

@Override,表示当前的方法定义覆盖了父类中的方法。必须要有相同的方法签名即(方法名,参数类型,参数顺序,参数个数)都一样。否则在编译过程中发出错误提示。

@Deprecated,对不应该再使用的方法添加注解,当使用这个方法的时候,会在编译时候显示提示信息。

@SuppressWarnings,关闭不当的编译器报警信息

四种元注解:

 @Target,表示该注解可以用什么地方。

TYPE : 类、接口或enum声明

FIELD: 域(属性)声明

METHOD: 方法声明

PARAMETER: 参数声明

CONSTRUCTOR: 构造方法声明

LOCAL_VARIABLE:局部变量声明

ANNOTATION_TYPE:注释类型声明

PACKAGE: 包声明

 @Retention,表示需要在什么级别保存该注解信息。

1. SOURCE//按照规定使用注释,但是并不将它保留到编译后的类文件中
2. CLASS//将注释保留在编译后的类文件中,但是在运行时忽略它 
3. RUNTIME//将注释保留在编译后的类文件中,并在第一次加载类时读取它  

 @Documented,将此注解包含到Javadoc中。

 @Inherited,允许子类继承父类的注解。


五、自定义Annocation
     先看一个简单的annocation
package com.cts.elt.annotation;

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

@Target(ElementType.TYPE )//此注解用在类上面
@Retention(RetentionPolicy.RUNTIME)//将注释保留在编译后的类文件中,并在第一次加载类时读取它 
@Documented

public @interface MyAnnotation1 {

        String value();

}

 上面这个MyAnnotation1.class文件包含一个值,下面来一个含有两个值的annotation:
package com.cts.elt.annotation;

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;

@Target(ElementType.METHOD )
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MyAnnotation2 {

        String description();

        boolean isAnnotation();

}

  关键是来看这两个自定义annotation的用法:
package com.cts.elt.annotation;

@MyAnnotation1 ("this isannotation1" )
public class AnnotationDemo {

     @MyAnnotation2(description = "this is annotation2", isAnnotation = true)
     public void sayHello() {

          System. out.println( "hello world!");

     }

}

 如果把@MyAnnotation1与@MyAnnotation2的位置换一换,会怎么样?(肯定报错啦!)

六、自定义Annocation高级篇
情景设计:设有一CLASS叫Student,其中有三个fields: 

private String name = "";

private int age = 0;

private String studentId = "";


 相应的每一个field有一对的set, get方法。 然后我在每个set方法上造一个annotation叫ValueBind的注解,其作用是: 只要set方法上带有ValueBind注解,它就会根据这个字段的类型把一个默认值,自动赋给Student类中相对应的field。
      1、先来看一下Student类: 
package com.cts.elt.annotation;

import java.io.Serializable;
import com.cts.elt.annotation.ValueBind.fieldType;

public class Student implements Serializable {
     
     private String name = "";

     public String getName() {
           return name;
     }

     @ValueBind(type = fieldType.STRING, value = "aa")
     public void setName(String name) {
           this.name = name;
     }

     public int getAge() {
           return age;
     }

     @ValueBind(type = fieldType.INT, value = "30")
     public void setAge( int age) {

           this.age = age;

     }

     public String getStudentId() {

           return studentId;

     }

     @ValueBind(type = fieldType.STRING, value = "101")
     public void setStudentId(String studentId) {

           this.studentId = studentId;

     }

     private int age = 0;

     private String studentId = "";

}

      2、自定义一个ValueBind的Annocation:
package com.cts.elt.annotation;

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;

@Target(ElementType.METHOD )
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ValueBind {

     enum fieldType {
           STRING, INT
     };

     fieldType type();

     String value();

}

首先这个annotation只能被标注在方法上;其次它含有两个值,一个是enum类型,一个是String类型
     3、利用Java类反射机制来实现我们的Annocation:
package com.cts.elt.annotation;

import java.lang.reflect.*;

public class PersistStudent {

     public static void main(String[] args) throws Exception {

          Object c = Class.forName("com.cts.elt.annotation.Student").newInstance();

           try {

              Method[] methodArray = c.getClass().getDeclaredMethods();

               for ( int i = 0; i < methodArray. length; i++) {

                    if (methodArray[i].isAnnotationPresent( ValueBind. class)) {//如果指定类型的注释存在于此元素上,则返回 true,否则返回 false。
                        
                         ValueBind annotation = methodArray[i].getAnnotation(ValueBind .class);//如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。

                        String type = String.valueOf(annotation.type());

                        String value = annotation.value();

                         if (type.equals( "INT")) {

                              methodArray[i].invoke(c, new Integer[] { new Integer(value) });

                        } else {

                              methodArray[i].invoke(c, new String[] { value });

                        }

                   }

              }

              Student annotaedStudent = (Student) c;

              System. out.println( "studentId====" + annotaedStudent.getStudentId()

              + "  studentnName====" + annotaedStudent.getName()

              + "   student Age====" + annotaedStudent.getAge());

          } catch (Exception e) {

               throw new Exception(e);

          }

     }

}

运行结果显示:
studentId====101  studentnName====aa   studentAge====30


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值