【Java EE 学习 24 上】【注解详解】

【Java EE 学习 24 上】【注解详解】

一、注解

  1.所有的注解都是类。

  2.所有的注解都是Annotation接口的子类。

接口摘要

Annotation

所有 annotation 类型都要扩展的公共接口。

  3.定义方式

public @interface TestAnnotation {
    
}

  4.可以注解的位置:任何地方都可以,但是要满足注解的具体限制,默认注解可以加在任意位置上

package com.kdyzm.anotation;

@TestAnnotation
public class Test {
    @TestAnnotation
    private String name;
    
    @TestAnnotation
    public void show(@TestAnnotation String name)
    {
        @TestAnnotation
        String age;
        System.out.println(name);
    }
}

  5.使用注解限制注解的位置

  使用@Target注解限制自定义注解的注解位置。

@Target(value={ElementType.METHOD})//声明只能对方法进行注解,接收数组参数

  具体可以限制的类型:ElementType枚举

/*
 * %W% %E%
 *
 * Copyright (c) 2006, 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
}
ElementType.java

  6.限制注解在运行时是否删除

  使用@Retention限制注解的存在范围

@Retention(value=RetentionPolicy.RUNTIME)//声明该注解在运行时保存,即使用方法isAnnotationPresent方法返回值是true

  具体的参数见:RetentionPolicy枚举(保留策略枚举)。

/*
 * %W% %E%
 *
 * Copyright (c) 2006, 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
}
RetentionPolicy.java

  7.注解的作用

    (1)编译时限制作用

public class MyServlet extends HttpServlet {
    @Override
    public void doGet(ServletRequest req,String name)
            throws ServletException, IOException {
    }
}

    因为父类没有这个方法,所以加上@Override注解之后就会编译报错。

    (2)运行时反射

    所有类的字节码对象Class、Field、Method、Constructor都拥有一个方法

 该方法用于判断类上、字段上、方法上、构造方法上是否存在注解,如果存在则返回true,否则返回false

 boolean

isAnnotation()
          如果此 Class 对象表示一个注释类型则返回 true。

    默认自定义注解在运行时删除,但是通过其它注解可以定义该自定义注解的生存范围。怎样定义见6。

  8.注解的实例化

    永远不要实例化注解类,因为注解类是通过系统通过反射实例化的。

  9.给注解定义属性/方法(官方说法为属性)。

    (1)value属性:官方推荐的属性,也是默认的属性,使用方法:public String value();(这种定义方法看上去好像是方法,但是实际上是属性,暂且为属性)

    (2)修饰符必须是public,可以存在static、final修饰,但是不能有其它修饰符。

    (3)默认值:使用关键字default定义,如果没有设置默认值,则在使用注解的时候必须显示赋值才能通过编译。

  10.注解定义示例。

package com.kdyzm.anotation;

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

@Target(value={ElementType.METHOD})//声明只能对方法进行注解,接收数组参数
@Retention(value=RetentionPolicy.RUNTIME)//声明该注解在运行时保存,即使用方法isAnnotationPresent方法返回值是true
public @interface MyAnnotation {
    public String value();
    public String name() default "noName";
}

二、使用注解小示例。

  1.获取注解的属性值。

  使用Class类、Field类、Method类、Constructor类的getAnnotation方法。  

 

<A extends Annotation>
A

getAnnotation(Class<A> annotationClass)
          如果存在该元素的指定类型的注释,则返回这些注释,否则返回 null。

  2.自定义注解小练习。

    (1)自定义注解MyAnnotation

package com.kdyzm.anotation;

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

@Target(value={ElementType.METHOD})//声明只能对方法进行注解,接收数组参数
@Retention(value=RetentionPolicy.RUNTIME)//声明该注解在运行时保存,即使用方法isAnnotationPresent方法返回值是true
public @interface MyAnnotation {
    public String value();
    public String name() default "noName";
}

    (2)在UseMyAnnotation类中使用自定义注解

package com.kdyzm.setOnMyAnnotation;

import com.kdyzm.anotation.MyAnnotation;
//使用自定义注解,该注解只能加在方法上。
public class UseMyAnnotation {
    private String name;
    private int age;
    @MyAnnotation("setName方法")
    public void setName(String name)
    {
        this.name=name;
    }
    @MyAnnotation("getName方法")
    private String getName()
    {
        return name;
    }
    private int getAge()
    {
        return age;
    }
    @MyAnnotation("setAge方法")
    public void setAge(int age)
    {
        this.age=age;
    }
}

    (3)解析UseMyAnnotation类的所有内容并对注解进行解析。

package com.kdyzm.demo;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

import com.kdyzm.anotation.MyAnnotation;

//测试自定义注解MyAnnotation的使用,使用MyAnnotation类和UseMyAnnotation类两个类
public class MyTest {
    public static void main(String[] args) throws Exception {
        String className="com.kdyzm.setOnMyAnnotation.UseMyAnnotation";
        Class cls=Class.forName(className);
        //实例化该类。
        Object obj=cls.newInstance();
        
        //获取该类中的所有方法
        Method []methods=cls.getDeclaredMethods();
        //遍历该方法数组。
        for(Method method:methods)
        {
            boolean flag=method.isAnnotationPresent(MyAnnotation.class);//判断是否进行了方法的注解
            if(flag)//如果进行了方法的注解
            {
                System.out.print("被注解的方法:");
                //判断是否是私有的方法
                if(method.getModifiers()==Modifier.PRIVATE)
                {
                    //如果是私有的方法则设置暴力破解
                    method.setAccessible(true);
                    System.out.println("该方法私有!方法名为:"+method.getName());
                }
                else
                {
                    System.out.println("该方法共有!方法名为:"+method.getName());
                }
                
                //如果被注解了,输出该注解属性值
                MyAnnotation annotation=method.getAnnotation(MyAnnotation.class);
                String value=annotation.value();
                String name=annotation.name();
                System.out.println("该注解的内容是:"+value+","+name);
            }
            else//说明是没有被注解的方法
            {
                System.out.print("没有被注解的方法:");
                //判断是否是私有的方法
                if(method.getModifiers()==Modifier.PRIVATE)
                {
                    //如果是私有的方法则设置暴力破解
                    method.setAccessible(true);
                    System.out.println("该方法私有!方法名为:"+method.getName());
                }
                else
                {
                    System.out.println("该方法共有!方法名为:"+method.getName());
                }
            }
            System.out.println();
        }
    }
}

    (4)运行结果。

没有被注解的方法:该方法私有!方法名为:getAge

被注解的方法:该方法共有!方法名为:setAge
该注解的内容是:setAge方法,noName

被注解的方法:该方法私有!方法名为:getName
该注解的内容是:getName方法,noName

被注解的方法:该方法共有!方法名为:setName
该注解的内容是:setName方法,noName