zoukankan      html  css  js  c++  java
  • Java 注解

    一、什么是java注解

             注解,顾名思义,注解,就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的。

             Java注解又叫java标注,java提供了一套机制,使得我们可以对方法、类、参数、包、域以及变量等添加标准(即附上某些信息)。且在以后某个时段通过反射将标注的信息提取出来以供使用。

    二、自定义Java标注

    1  为什么要自定义注解

             Java从1.5版本以后默认内置三个标注:

    Ø @Override:只能用在方法之上的,用来告诉别人这一个方法是改写父类的。

    Ø @Deprecated:用来表示某个类的属性或方法已经过时,不想别人再用时,在属性和方法上用@Deprecated修饰;编译的时候会用产生警告信息,可以设定在程序里的所有的元素上.

    Ø @SuppressWarnings:这一个类型可以来暂时把一些警告信息消息关闭.

    但是,仅仅这三个标注是不能满足我们开发时一些需求的。所以java允许我们自定义注解来使用。

    2  如何自定义注解

    java用  @interface xxx{ } 定义一个注解 @xxx,一个注解是一个类

    自定义步骤大致分为两步:

    1,              通过@interface关键字声明注解名称,以及注解的成员属性或者叫做注解的参数。

    2,              使用java内置的四个元注解对这个自定义标注的功能和范围进行一些限制

    问题来了,什么是元注解?

    3  什么是元注解

    元注解,就是定义注解的注解,也就是说这些元注解是的作用就是专门用来约束其它注解的注解。请区别上面那三个注解,他们也是通过元注解定义而来的。

    元注解有哪些呢,主要有四个@Target,@Retention,@Documented,@Inherited?

    1.  * 元注解有:@Target,@Retention,@Documented,@Inherited

    2.  * 

    3.  *     @Target 表示该注解用于什么地方,可能的 ElemenetType 参数包括:

    4.  *         ElemenetType.CONSTRUCTOR 构造器声明

    5.  *         ElemenetType.FIELD 域声明(包括 enum 实例)

    6.  *         ElemenetType.LOCAL_VARIABLE 局部变量声明

    7.  *         ElemenetType.METHOD 方法声明

    8.  *         ElemenetType.PACKAGE 包声明

    9.  *         ElemenetType.PARAMETER 参数声明

    10. *         ElemenetType.TYPE 类,接口(包括注解类型)或enum声明

    11. *         

    12. *     @Retention 表示在什么级别保存该注解信息。可选的 RetentionPolicy 参数包括:

    13. *         RetentionPolicy.SOURCE 注解仅存在于源码中,注解将被编译器丢弃.即不会留在class(字节码文件)文件中

    14. *         RetentionPolicy.CLASS 注解在class文件中可用,但会被VM丢弃,即在运行时无法获得

    15. *         RetentionPolicy.RUNTIME 注解会在class字节码文件中存在,VM在运行期也保留注释,因此在运行时可以通过反射机制读取注解的信息。

    16. *         

    17. *     @Documented 默认情况下,注解不会在javadoc中记录,但是可以通过这个注解来表明这个注解需要包含在 javadoc 中

    18. *     

    19. *     @Inherited 允许子类继承父类中的注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。

    4 自定义及使用注解示例

    自定义注解的语法要求:

    1 @Target({ElementType.METHOD,ElementType.TYPE})

    2 @Retention(RetentionPolicy.RUNTIME)

    3 @Inherited

    4 @Documented

    5 ublic @interface Description {

         String desc();

         String author();

         int age() default 18;

     }

    首先我们要明确这不是一个接口,它是使用@interface关键字定义的一个注解。

    然后我们看下面的几个方法,String desc();虽然它很类似于接口里面的方法,其实它在注解里面只是一个成员变量(成员以无参无异常的方式声明),int age() default 18;(成员变量可以用default指定一个默认值的)。

    最后我们要知道:

    ①.成员类型是受限制的,合法的类型包括基本的数据类型以及String,Class,Annotation,Enumeration等。

    ②.如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=)。

    ③.注解类可以没有成员,没有成员的注解称为标识注解。

    使用自定义注解:

    使用注解的语法:

    @<注解名>(<成员名1>=<成员值1>,<成员名2>=<成员值2>,…)

    案例:

    1 @Description(desc="i am Color",author="boy",age=18)

    2 public String Color() {

    3    return "red";

    4 }

    这里的Description是我们刚才在自定义注解语法要求里面定义的注解噢,然后我们可以给它的每一个成员变量赋值,注意数据类型。值得注意的是,因为我们前面定义的作用域是在方法和类接口上,所以这个注解在Color()方法上使用是没问题的。

    解析注解

    概念:

    通过反射获取类 、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑。

       Java使用Annotation接口来代表程序元素前面的注解,该接口是所有Annotation类型的父接口。相应地,Java在java.lang.reflect 包下新增了AnnotatedElement接口,该接口代表程序中可以接受注解的程序元素。

       实际上,java.lang.reflect 包所有提供的反射API扩充了读取运行时Annotation信息的能力。当一个Annotation类型被定义为运行时的Annotation后,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。

       AnnotatedElement接口是所有程序元素(Field、Method、Package、Class和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的如下七个方法来访问Annotation信息:

    <T extends Annotation> T getAnnotation(Class<T> annotationClass) :返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null;

    Annotation[] getDeclaredAnnotation(Class<T>):返回该程序元素上存在的、指定类型的注解,如果该类型注解不存在,则返回null;与此接口中的其他方法不同,该方法将忽略继承的注解;

    Annotation[] getAnnotations():返回该程序元素上存在的所有注解;

    Annotation[] getDeclaredAnnotations():返回直接存在于此元素上的所有注释。与此接口中的其他方法不同,该方法将忽略继承的注解;

    Annotation[] getAnnotationsByType(Class<T>):返回直接存在于此元素上指定注解类型的所有注解;

    Annotation[] getDeclaredAnnotationsByType(Class<T>):返回直接存在于此元素上指定注解类型的所有注解。与此接口中的其他方法不同,该方法将忽略继承的注解;

    boolean isAnnotationPresent(Class<?extends Annotation> annotationClass):判断该程序元素上是否包含指定类型的注解,存在则返回true,否则返回false;

     自定义一个类级别的标注Description

    package lighter.javaeye.com;

       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.TYPE)//这个标注应用于类

       @Retention(RetentionPolicy.RUNTIME)//标注会一直保留到运行时

       @Documented//将此注解包含在javadoc中

       public @interface Description {

           String value();

       }

      

       首先,一个注解一般需要2个元注解修饰:

       @Target(ElementType.FIELD)

       @Retention(RetentionPolicy.RUNTIME)

       具体作用上面已解释。

       所有的注解都会有一个类似于“func”的部分。这个可以理解为注解的参数。

             再定义个方法级别的注解Name

       package lighter.javaeye.com;

       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与@Description里的不同,参数成员也不同

       @Target(ElementType.METHOD)

       @Retention(RetentionPolicy.RUNTIME)

       @Documented

       public @interface Name {

           String originate();

           String community();

       }

             然后使用以上两个注解

    package lighter.javaeye.com;

    @Description(value="test description")

    public class DescTest{

             @Name(originate="panda",community="javatest")

             public String getName()

             {

                       return null;

             }

           

             @Name(originate="tiger ",community="spider")

             public String getName2()

             {

                       return "this is a case~”

             }

    }

    说明:其中标注“@Description(value=" test description")”,可以写成“@Description("test description ") ”,结果也是一样的。因为Description标注定义的时候其参数(或者说属性)为value。而value比较特殊,它在被指定参数的时候可以不用显示的写出来。当然如果定义的时候参数名不是value而是其它的比如des,那么使用注解的时候,必须显示写出参数名,然后再赋值:@Description(Des=”xxx”)

                                                                                                                                                  

    提取出注解的信息

    package lighter.javaeye.com;

     import java.lang.reflect.Method;

     import java.util.HashSet;

     import java.util.Set;

     public class TestAnnotation {

             /**

              * author lighter

              * 说明:具体关天Annotation的API的用法请参见javaDoc文档

              */

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

           String CLASS_NAME = "lighter.javaeye.com.JavaTest";

           Class test = Class.forName(CLASS_NAME);

           Method[] method = test.getMethods();

           boolean flag = test.isAnnotationPresent(Description.class);

            if(flag)

            {

                     Description des = (Description)test.getAnnotation(Description.class);

                     System.out.println("描述:"+des.value());

                     System.out.println("-----------------");

            }

          

            //把JavaEyer这一类有利用到@Name的全部方法保存到Set中去

            Set<Method> set = new HashSet<Method>();

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

            {

                     boolean otherFlag = method[i].isAnnotationPresent(Name.class);

                     if(otherFlag) set.add(method[i]);

            }

            for(Method m: set)

            {

                     Name name = m.getAnnotation(Name.class);

                     System.out.println(name.originate());

                     System.out.println("the community:"+name.community());

            }

         }

    }

    注意事项:

    所有的Annotation会自动继承java.lang.annotation这一个接口,所以不能再去继承别的类或是接口.

       最重要的一点,Annotation类型里面的参数该怎么设定:

       第一,只能用public或默认(default)这两个访问权修饰.例如,String value();这里把方法设为defaul默认类型.

       第二,参数成员只能用基本类型byte,short,char,int,long,float,double,boolean八种基本数据类型和String,Enum,Class,annotations等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String.

    注解用例

    注解的功能很强大,Spring和Hebernate这些框架在日志和有效性中大量使用了注解功能。注解可以应用在使用标记接口的地方。不同的是标记接口用来定义完整的类,但你可以为单个的方法定义注释,例如是否将一个方法暴露为服务。

    在最新的servlet3.0中引入了很多新的注解,尤其是和servlet安全相关的注解。

    HandlesTypes –该注解用来表示一组传递给ServletContainerInitializer的应用类。

    HttpConstraint – 该注解代表所有HTTP方法的应用请求的安全约束,和ServletSecurity注释中定义的HttpMethodConstraint安全约束不同。

    HttpMethodConstraint – 指明不同类型请求的安全约束,和ServletSecurity 注解中描述HTTP协议方法类型的注释不同。

    MultipartConfig –该注解标注在Servlet上面,表示该Servlet希望处理的请求的 MIME 类型是 multipart/form-data。

    ServletSecurity 该注解标注在Servlet继承类上面,强制该HTTP协议请求遵循安全约束。

    WebFilter – 该注解用来声明一个Server过滤器;

    WebInitParam – 该注解用来声明Servlet或是过滤器的中的初始化参数,通常配合 @WebServlet 或者 @WebFilter 使用。

    WebListener –该注解为Web应用程序上下文中不同类型的事件声明监听器。

    WebServlet –该注解用来声明一个Servlet的配置。

  • 相关阅读:
    Ajax技术的工作原理
    《统计学习方法》第七章,支持向量机
    《西瓜书》第四章,决策树3
    OpenCL 矩阵乘法
    MPI 集合通信函数 MPI_Reduce(),MPI_Allreduce(),MPI_Bcast(),MPI_Scatter(),MPI_Gather(),MPI_Allgather(),MPI_Scan(),MPI_Reduce_Scatter()
    有关CUBLAS中的矩阵乘法函数
    TensorFlow 笔记04
    TensorFlow 笔记03-TensoeFlow 和 TensorRT 调试的一些方法
    TensorFlow 笔记02-mnist 的 tensorRT 实现,从 .npz 文件中加载参数进行推理
    TensorFlow 笔记01-mnist 的两种 tensorFlow 实现,保存和加载模型的三种方法
  • 原文地址:https://www.cnblogs.com/pandaly/p/10342623.html
Copyright © 2011-2022 走看看