我们知道注解是在JDK1.5引入的,可能有的人没有用过注解,所以感觉注解这个东西没有什么用,但是深入了解注解,对以后学习框架有所帮助的,后面提到的JavaWeb的框架中很多都是基于注解的技术,
其实注解你可以把他认为是一种标记,和接口差不多,我们知道有些接口只起到标记作用(通常叫做标记接口如:Serializable,Cloneable等,就是接口中没有任何东西,只做为一种标记),下面来看一下注解的定义和使用的方法:
定义一个注解和接口差不多:使用关键字@interface
代码如下:
- package com.annotation.demo;
- import java.lang.annotation.ElementType;
- import java.lang.annotation.Retention;
- import java.lang.annotation.RetentionPolicy;
- import java.lang.annotation.Target;
- @Retention(RetentionPolicy.RUNTIME)
- //javac将源程序编译成class文件,在这个过程中类上的注解是否保留到class文件中
- //注解的生命周期的三个阶段:源程序,class文件,字节码
- //默认值是在class阶段
- //Override SuppressWarning Deprecated:按照编译器的标准来判断这三个阶段
- @Target({ElementType.ANNOTATION_TYPE,ElementType.TYPE,ElementType.CONSTRUCTOR,ElementType.FIELD,ElementType.LOCAL_VARIABLE,ElementType.METHOD,ElementType.PACKAGE,ElementType.PARAMETER})
- //注解添加的目标
- public @interface MyAnnotation{
- String color() default "red";//属性String
- int[] value() default {1};//属性int[],这是个特殊的属性,如果只有一个value属性需要去设置值,可以不需要设置"value="
- MyEnum enums() default MyEnum.ONE;//属性enum,返回值是MyEnum枚举
- MetaAnnotation annotation() default @MetaAnnotation("red");//注解属性
- //静态常量
- boolean isRunning = false;
- }
首先来看一下@Retention注解的作用:他的作用是标记该注解的生命周期(即三个阶段:Java源程序,class文件,字节码),看一下他的源代码:
- /*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package java.lang.annotation;
- /**
- * Indicates how long annotations with the annotated type are to
- * be retained. If no Retention annotation is present on
- * an annotation type declaration, the retention policy defaults to
- * {@code RetentionPolicy.CLASS}.
- *
- * <p>A Retention meta-annotation has effect only if the
- * meta-annotated type is used directly for annotation. It has no
- * effect if the meta-annotated type is used as a member type in
- * another annotation type.
- *
- * @author Joshua Bloch
- * @since 1.5
- */
- @Documented
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.ANNOTATION_TYPE)
- public @interface Retention {
- RetentionPolicy value();
- }
- /*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package java.lang.annotation;
- /**
- * Annotation retention policy. The constants of this enumerated type
- * describe the various policies for retaining annotations. They are used
- * in conjunction with the {@link Retention} meta-annotation type to specify
- * how long annotations are to be retained.
- *
- * @author Joshua Bloch
- * @since 1.5
- */
- public enum RetentionPolicy {
- /**
- * Annotations are to be discarded by the compiler.
- */
- SOURCE,
- /**
- * Annotations are to be recorded in the class file by the compiler
- * but need not be retained by the VM at run time. This is the default
- * behavior.
- */
- CLASS,
- /**
- * Annotations are to be recorded in the class file by the compiler and
- * retained by the VM at run time, so they may be read reflectively.
- *
- * @see java.lang.reflect.AnnotatedElement
- */
- RUNTIME
- }
SOURCE:是将注解保存在源程序中,但是会被编译器遗弃的,就是不会保留到class文件中了,而且这个是默认值
CLASS:是将注解会被编译器保存到class文件中,但是不会保留到VM运行的时候,就是会被在JVM加载字节码的时候遗弃
RUNTIME:是将注解保存到运行的时候,这时候也就可以使用反射技术获取到这个注解的实例对象了
下面来看一下例子:
在定义一个注解,这个注解是被定义在MyAnnotation注解中的,我们叫这样的注解是原注解:
- package com.annotation.demo;
- public @interface MetaAnnotation {
- String name() default "red";
- String value();
- }
还有我们自定义了枚举:
- package com.annotation.demo;
- public enum MyEnum {
- ONE,TWO,THREE;
- }
在来看一下,使用了MyAnnotation注解的类:
- package com.annotation.demo;
- @MyAnnotation(color="red",value={1,2,3},enums=MyEnum.ONE)
- public class UseAnnotation {
- public void fun(){
- }
- }
- package com.annotation.demo;
- public class AnnotationTest {
- public static void main(String[] args){
- //UserAnnotation类中使用到了MyAnnotation自定的注解
- UseAnnotation.class.isAnnotationPresent(MyAnnotation.class);
- //获取UserAnnotation中上的注解
- MyAnnotation annotation = (MyAnnotation) UseAnnotation.class.getAnnotation(MyAnnotation.class);
- //打印注解
- System.out.println(annotation);
- System.out.println(annotation.color());
- System.out.println(annotation.enums());
- System.out.println(annotation.value().length);
- }
- }
打印出来了注解
下面我们将MyAnnotation注解中的@Retention(RetentionPolicy.RUNTIME)注解改成@Retention(RetentionPolicy.SOURCE),这时候在运行:
发现运行打印的枚举结果是null,如果将@Retention(RetentionPolicy.CLASS)效果也是一样的,这个就是和我们上面所说的那样,这个注解没有保存到运行的时候,我们是无从类中获取到注解的实例对象的,这样@Retention注解类型的作用就清楚了,刚开始搞这个东西的时候,总是打印出来的是null,而@Retention的默认值是SOURCE,找了很多资料,才搞定的,很纠结呀!
下面在来看一下@Target注解:
源代码如下:
- /*
- * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package java.lang.annotation;
- /**
- * Indicates the kinds of program element to which an annotation type
- * is applicable. If a Target meta-annotation is not present on an
- * annotation type declaration, the declared type may be used on any
- * program element. If such a meta-annotation is present, the compiler
- * will enforce the specified usage restriction.
- *
- * For example, this meta-annotation indicates that the declared type is
- * itself a meta-annotation type. It can only be used on annotation type
- * declarations:
- * <pre>
- * @Target(ElementType.ANNOTATION_TYPE)
- * public @interface MetaAnnotationType {
- * ...
- * }
- * </pre>
- * This meta-annotation indicates that the declared type is intended solely
- * for use as a member type in complex annotation type declarations. It
- * cannot be used to annotate anything directly:
- * <pre>
- * @Target({})
- * public @interface MemberType {
- * ...
- * }
- * </pre>
- * It is a compile-time error for a single ElementType constant to
- * appear more than once in a Target annotation. For example, the
- * following meta-annotation is illegal:
- * <pre>
- * @Target({ElementType.FIELD, ElementType.METHOD, ElementType.FIELD})
- * public @interface Bogus {
- * ...
- * }
- * </pre>
- */
- @Documented
- @Retention(RetentionPolicy.RUNTIME)
- @Target(ElementType.ANNOTATION_TYPE)
- public @interface Target {
- ElementType[] value();
- }
看一下ElementType源代码:
- /*
- * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
- * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
- */
- package java.lang.annotation;
- /**
- * A program element type. The constants of this enumerated type
- * provide a simple classification of the declared elements in a
- * Java program.
- *
- * <p>These constants are used with the {@link Target} meta-annotation type
- * to specify where it is legal to use an annotation type.
- *
- * @author Joshua Bloch
- * @since 1.5
- */
- public enum ElementType {
- /** Class, interface (including annotation type), or enum declaration */
- TYPE,
- /** Field declaration (includes enum constants) */
- FIELD,
- /** Method declaration */
- METHOD,
- /** Parameter declaration */
- PARAMETER,
- /** Constructor declaration */
- CONSTRUCTOR,
- /** Local variable declaration */
- LOCAL_VARIABLE,
- /** Annotation type declaration */
- ANNOTATION_TYPE,
- /** Package declaration */
- PACKAGE
- }
TYPE:是Java1.5引入的新类型,他概括了所有的类型,不止是Class类,还有枚举Enum等,所以这里没有用CLASS类型了
FIELD:是类中的字段
METHOD:是类中的方法
PARAMETER:是方法中的形参(传递的参数类型)
CONSTRUCTOR:是构造方法
LOCAL_VARIABLE:方法中定义的变量
ANNOTATION_TYPE:注解可以添加在注解中
PACKAGE:注解添加在包中
这部分比较简单,这里就不掩饰了,我们一般是把这7个值都设置进去(如果没有特殊要求的话)
下面来看一下注解中的定义和使用方法:
- public @interface MyAnnotation{
- String color() default "red";//属性String
- int[] value() default {1};//属性int[],这是个特殊的属性,如果只有一个value属性需要去设置值,可以不需要设置"value="
- MyEnum enums() default MyEnum.ONE;//属性enum,返回值是MyEnum枚举
- MetaAnnotation annotation() default @MetaAnnotation("red");//注解属性
- //静态常量
- boolean isRunning = false;
- }
注解中定义的属性和接口中定义的是有区别的,注解中定义一个属性:Void fun() default ===>返回类型 属性名称 默认值,使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。在定义注解时,不能继承其他的注解或接口。@interface用声明一个注解,其中的每一个方法实际上是声明了一个配置参数。方法的名称就是参数的名称,返回值类型就是参数的类型(返回值类型只能是基本类型、Class、String、enum)。可以通过default来声明参数的默认值。当然注解中定义的类型有:注解参数的可支持数据类型:
1.所有基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String类型
3.Class类型
4.enum类型
5.Annotation类型
6.以上所有类型的数组
当然注解中也可以定义一个字段,这个字段的类型和接口中的类型是一样的,默认的是静态常量,下面来看一下注解的使用方法:
- package com.annotation.demo;
- @MyAnnotation(color="red",value={1,2,3},enums=MyEnum.ONE)
- public class UseAnnotation {
- public void fun(){
- }
- }
- public @interface Retention {
- RetentionPolicy value();
- }
@Retention(RetentionPolicy.SOURCE)
我们发现这个使用没有用到“=”按照常理应该是:value=RetentionPolicy.SOURCE这样使用的,所以这里value就是个特殊的属性了,名称不能写错了,是value,当一个注解中有且只有一个属性value的时候,我们可以省略"=",直接这样赋值,这里要注意是有且仅有一个,如果注解中有多个属性,这时候就不能这样操作了,像我们自定义的注解MyAnnotation中还有其他的注解,所以就不能省略"="了,当然如果你在其他的属性中在定义一个默认值就是default,这时候也还是可以省略“=”的,其他的情况就不行了
写到这里就算结束了,这个注解是很简单的,他的作用也很明白,就是标记的作用,我们需要自己顶一个注解管理器(spring中就是这样做的,这样就可以查到这个类上的所有标记了,通过这个标记在对这个类进行相应的操作)