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

时间:2023-03-08 17:39: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