java注解

来源:互联网 发布:医学网络教育 编辑:程序博客网 时间:2024/06/09 18:24

一、什么是注解

1)例如,@Override、@SuppressWarning这种

2)定义:注解(也被称为元数据)是指程序功能外,在代码中添加的额外信息,这些信息可以用来修饰、标识功能代码,但不影响代码运行

3)作用:类似于代码中的注释,所不同的是注解不是提供代码功能的说明,而是实现程序功能的重要组成部分

一般可以取代复杂的配置文件(你了解SSM之类的框架的话,就会知道注解方便配置了),用于告之容器管理者某个类、方法的行为


二、注解的形式

注解是以‘@注解名’在代码中存在的

根据注解参数的个数,我们可以将注解分为:

1)标记注解:没有变量,只有名称标识。例如:@annotation

2)单值注解:在标记注解的基础上提供一段数据。如:@annotation(“data”)

3) 完整注解:可以包括多个数据成员,每个数据成员由名称和值构成。如:@annotation(val1=“data1”, val2=“data2”)


三、创建自定义注解

java已经定义了一些注解,但是我们想自己弄一些,怎么办呢

1)定义注解,例子:

import java.lang.annotation.ElementType;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;import java.lang.annotation.Target; @Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Test {//不带变量的注解}

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Entity {//带变量的注解public int type() default -1;public String name();}

2)元注解(注解的注解),是java定义的用于创建注解的工具,它们本身也是注解。Java中的元注解包括四个注解,分别是:

@Target

@Retention

@Document

@Inherited


2.1)@Taget注解表明了自定义注解的作用域。可能的作用域被定义在一个枚举类型中:ElementType。

ElementType中的常量值如下:

ANNOTATION_TYPE :作用在注解类型上的注解

CONSTRUCTOR :作用在构造方法上的注解

FIELD :作用在属性上的注解

LOCAL_VARIABLE :作用在本地变量上的注解

METHOD :作用在方法上的注解

PACKAGE :作用在包上的注解

PARAMETER :作用在参数上的注解

Type :作用在类、接口或枚举上的注解


2.2)@Retention用于声明注解信息的保留策略,可选的级别被存放在枚举RetentionPolicy中,该枚举中的常量值如下:

RetentionPolicy.SOURCE :注解信息仅保留在源文件中,编译时将丢弃注解信息,此时类似于注释。

RetentionPolicy.CLASS :注解信息将被编译进Class文件中,但这些注解信息在运行时将丢弃。

RetentionPolicy.RUNTIME:注解信息将被保留到运行时,你可以通过反射来读取这些注解信息,这个比较有用。


2.3)@Document

表明制作javadoc时,是否将注解信息加入文档。如果注解在声明时使用了@Documented,则在制作javadoc时注解信息会加入javadoc


2.4)@Inherited

表明注解是否会被子类继承,缺省情况是不继承的。当注解在声明时,使用了@Inherited注解,则该注解会被使用了该注解的类的子类所继承


3)注解的参数

3.1)参数类型必须使用指定参数类型

所有基本类型,包括(int,float,boolean)

String

Class

enum

Annotation

以及以上类型的数组


3.2)注解参数的赋值要求

编译器要求注解的参数不能是不确定值,即要么在定义注解的时候就进行赋值,要么在使用的时候进行赋值


4)注解的使用

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface ID {public String value();public String description() default "";}public class Person {@ID(“personID”)    //系统默认为未赋值的参数赋值private Integer id;}

5)注解的嵌套

@Target(ElementType.FIELD)@Retention(RetentionPolicy.RUNTIME)public @interface ID {public String value() default "id";}@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Entity {public String name() default "";public ID id() default @ID("id");}

四、注解处理器

即使自己定义了注解又怎么样,好像和注释没差别啊。。这就要说到注解处理器了,它能利用反射机制读取分析注解

1)注意:

要想使用反射去读取注解,必须将Retention的值选为Runtime


2)例子:

 需求:实现一个简单的注解处理,该处理器用于提取指定类的公共方法,然后构建一个抽象接口类。

 设计:

           1. 定义ExtractInterface 注解

@Target(ElementType.TYPE)//想好这个注解用在哪里,类还是方法,还是属性,还是其它@Retention(RetentionPolicy.RUNTIME)public @interface ExtractInterface {public String value();}

           2. 定义AnnotationProcessor 接口(注解处理器接口)

public interface AnnotationProcessor {public boolean process(Class<?> clazz) throws Exception;//自己定义的参数和返回值,想怎么就怎么,不要有拘束}


           3. AnnotationProcessor 的实现类ExtractProcessor(注解处理器)

/** * 抽象接口注解处理器 该处理器负责抽象指定类的公共方法,然后生成指定的接口 */public class ExtractProcessor implements AnnotationProcessor {/** * 暴露的外部接口方法,使用该方法需要传入指定类的Class对象 处理的流程如下: 1.获取@ExtractInterface注解 * 2.如果注解该类拥有指定注解,则创建一个StringBuilder用于临时存放生成代码 3.在StringBuilder中添加包信息 * 4.在StringBuilder中添加接口信息 5.遍历指定类声明的方法集合,并在StringBuilder加入公共方法信息 6.生成接口文件 */public boolean process(Class<?> clazz) throws Exception {ExtractInterface extractInterface = this.getExcactInterface(clazz);if (extractInterface != null) {StringBuilder sb = new StringBuilder();this.addPackage(sb, clazz);this.addInterface(sb, extractInterface);Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) { // 遍历指定类声明的方法if (method.getModifiers() == Modifier.PUBLIC) { // 如果获取的方法为公共方法sb = this.addMethod(sb, method); // 添加方法信息}}sb.append("}");this.createFile(sb, clazz, extractInterface); // 创建接口文件return true;}return false;}/** * 获取@ExtractInterface注解,使用该方法需要传入指定类的Class对象 处理流程如下: 1.遍历该类上的所有注解 * 2.如果注解的类型为@ExtractInterface,则返回该注解,负责返回null *  * @param clazz *            指定类的Class对象 * @return 类上声明的@ExtractInterface注解 */private ExtractInterface getExcactInterface(Class<?> clazz) {Annotation[] annotations = clazz.getAnnotations();for (Annotation annotation : annotations) {if (annotation.annotationType() == ExtractInterface.class) {return (ExtractInterface) annotation;}}return null;}/** * 向StringBuilder中添加包信息,使用该类需要传入StringBuilder和指定类的Class对象 */private StringBuilder addPackage(StringBuilder sb, Class<?> clazz) {sb.append("package ");sb.append(clazz.getPackage().getName());sb.append(";");sb.append("\n");return sb;}/** * 向StringBuilder中添加接口信息,使用该类需要传入StringBuilder和@ExtractInterface注解对象 */private StringBuilder addInterface(StringBuilder sb, ExtractInterface anno) {sb.append("public  interface ");sb.append(anno.value()); // 根据@ExtractInterface的value参数来确定接口名称sb.append("{");sb.append("\n");return sb;}/** * 向StringBuilder中添加方法信息,使用该方法传入StringBuilder和指定的方法 处理流程如下: 1.添加修饰符 * 2.添加返回值类型 3.添加方法名称 4.遍历参数类型,并向StringBuilder中添加参数 */private StringBuilder addMethod(StringBuilder sb, Method method) {sb.append(TAB + "public ");sb.append(method.getReturnType().getCanonicalName() + BLANK); // 添加返回值类型sb.append(method.getName() + BLANK); // 添加方法名sb.append("(");Class[] paras = method.getParameterTypes(); // 获取参数类型集合String arg = "arg"; // 参数名得前半部分Integer argIndex = 0; // 参数索引for (Class<?> para : paras) { // 遍历方法的参数类型sb.append(para.getCanonicalName() + BLANK); // 添加参数类型sb.append(arg + argIndex); // 添加参数名称,参数名称由arg+索引组成sb.append("," + BLANK);argIndex++;}if (argIndex > 0) { // 去除多余的逗号和空格sb = new StringBuilder(sb.substring(0, sb.length() - 2));}sb.append(")");sb.append(";");sb.append("\n");return sb;}/** * 创建接口文件 */private void createFile(StringBuilder sb, Class<?> clazz,ExtractInterface ext) throws Exception {String path = clazz.getPackage().getName();path = path.replace(".", "\\");String url = System.getProperty("user.dir") + "\\src\\" + path + "\\"+ ext.value() + ".java";FileOutputStream fileWriter;fileWriter = new FileOutputStream(url);fileWriter.write(sb.toString().getBytes("UTF-8"));fileWriter.flush();fileWriter.close();System.out.println(url);}public static final String BLANK = " ";public static final String TAB = "\t";}

           4. 定义使用了ExtractInterface 注解的测试类Person

@ExtractInterface("IPerson")public class Person {public void speak(String message){System.out.println(message);}public void useTool(String toolName){System.out.println(toolName);}}

           5. 编写测试程序AnnotationTest

public class AnnotationTest {public static void main(String[] args) throws Exception {AnnotationProcessor processor = new ExtractProcessor();processor.process(Person.class);}}


6、结果,在目录下生成了一个IPerson.java文件,内容如下

public  interface IPerson{public void speak (java.lang.String arg0);public void useTool (java.lang.String arg0);}