【Java EE 学习 24 上】【注解详解】
一、注解
1.所有的注解都是类。
2.所有的注解都是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 }
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 }
7.注解的作用
(1)编译时限制作用
public class MyServlet extends HttpServlet { @Override public void doGet(ServletRequest req,String name) throws ServletException, IOException { } }
因为父类没有这个方法,所以加上@Override注解之后就会编译报错。
(2)运行时反射
所有类的字节码对象Class、Field、Method、Constructor都拥有一个方法
|
|
|
|
默认自定义注解在运行时删除,但是通过其它注解可以定义该自定义注解的生存范围。怎样定义见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方法。
|
||
|
|
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