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
@Inherited2.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);}}
public interface IPerson{public void speak (java.lang.String arg0);public void useTool (java.lang.String arg0);}
- Java注解-自定义注解
- Java注解----自定义注解
- Java注解自定义注解
- Java注解--四种元注解
- Java注解-三种內建注解
- 【Java】【注解】自定义注解
- java注解
- java注解
- java注解
- java 注解
- Java注解
- java 注解
- Java 注解
- Java注解
- java 注解
- JAVA注解
- Java注解
- Java注解
- 欢迎使用CSDN-markdown编辑器
- 查看以及修改mysql默认字符集的方法
- RedHat6.5安装kafka单机
- Linux userdel 命令解析示例
- select获取选中的内容
- java注解
- MakeFile 文件的作用
- Kafka分区分配策略(Partition Assignment Strategy)
- java判断是否含有特殊字符
- 【Azure】创建负载均衡器连接Linux虚拟机
- myeclipse2014Customize Persperctive没反应,加入filter功能
- c++ cmath常用库函数
- 前端几万条数据显示猜想
- 百度云大文件使用迅雷下载