一、元数据
- 所谓元数据就是数据的数据。也就是说,元数据是描述数据的。
- 就象数据表中的字段一样,每个字段描述了这个字段下的数据的含义
- 元数据可以用与创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查
- 许多元数据工具,如XDocklet,讲这些功能添加到核心java语言中,暂时成为java变成功能的一部分
- 一般来说,元数据的好处分为三类:
- -文档编制,编译器检查和代码分析
- --代码级文档最常被引用
- ---元数据提供了一种有用的方法来指明方法是否取决于其他方法,他们是否完整,特定类是否必须引用其他类,等等
二、什么是注解
- java中的注解就是java源代码的元数据
- 也就是说注解是用来描述java源代码的
- 基本语法就是@后面跟注解的名称
- java5以上的版本都支持,有预定义的注解,也可以自定义注解
- 用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能
- 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。包含在 java.lang.annotation 包中。
- 注解使得Java源代码中不但可以包含功能性的实现代码,还可以添加元数据。
- 注解的功能类似于代码中的注释,所不同的是注解不是提供代码功能的说明,而是实现程序功能的重要组成部分。
- Java注解已经在很多框架中得到了广泛的使用,用来简化程序中的配置。
三、元注解
元注解是指注解的注解。包括 @Retention @Target @Document @Inherited四种
1、@Retention: 定义注解的保留策略 @Retention(RetentionPolicy.SOURCE) //注解仅存在于源码中,在class字节码文件中不包含 @Retention(RetentionPolicy.CLASS) // 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得, @Retention(RetentionPolicy.RUNTIME) // 注解会在class字节码文件中存在,在运行时可以通过反射获取到 2、@Target:定义注解的作用目标 @Target(ElementType.TYPE) //接口、类、枚举、注解 @Target(ElementType.FIELD) //字段、枚举的常量 @Target(ElementType.METHOD) //方法 @Target(ElementType.PARAMETER) //方法参数 @Target(ElementType.CONSTRUCTOR) //构造函数 @Target(ElementType.LOCAL_VARIABLE)//局部变量 @Target(ElementType.ANNOTATION_TYPE)//注解 @Target(ElementType.PACKAGE) //包 elementType 可以有多个,一个注解可以为类的,方法的,字段的等等 @Target({ElementType.TYPE,ElementType.METHOD}) 3、@Documented:指示某一类型的注解将通过 javadoc 和类似的默认工具进行文档化。 4、@Inherited:说明子类可以继承父类中的该注解
四、Annotation的工作原理
- JDK5.0中提供了注解的功能,允许开发者定义和使用自己的注解类型。
- 该功能由一个定义注解类型的语法和描述一个注解声明的语法,读取注解的API,一个使用注解修饰的class文件和一个注解处理工具组成。
- Annotation并不直接影响代码的语义,但是他可以被看做是程序的工具或者类库。
- 它会反过来对正在运行的程序语义有所影响。
- Annotation可以从源文件、class文件或者在运行时通过反射机制多种方式被读取。
五、java.lang包中的三个注解
Override 表示一个方法声明打算重写超类中的另一个方法声明。 如果方法利用此注解类型进行注解但没有重写超类方法,则编译器会生成一条错误消息。 @Target(value=METHOD) @Retention(value=SOURCE) public @interface Override{} Deprecated 用 @Deprecated 注释的程序元素,不鼓励程序员使用这样的元素,通常是因为它很危险或存在更好的选择。 在使用不被赞成的程序元素或在不被赞成的代码中执行重写时,编译器会发出警告。 @Documented @Retention(value=RUNTIME) public @interface Deprecated{} SuppressWarnings 指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。 @Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE}) @Retention(value=SOURCE) public @interface SuppressWarnings{ String[] value(); }
六、自定义注解
- 使用@interface自定义注解时,自动继承了java.lang.annotation.Annotation接口,由编译程序自动完成其他细节。
- 在定义注解时,不能继承其他的注解或接口
- 注解的属性可以是任意数据类型,int String Class 注解 数组。。。。都可以作为注解的属性
- 注解和接口一样,也可以定义其他的元素,如常量等
//自定义最简单的注解
public @interface MyAnnotation {
}
//使用自定义注解
public class AnnotationTest2 {
@MyAnnotation
public void execute(){
System.out.println("method");
}
}
//添加变量 public @interface MyAnnotation { String value(); } //使用自定义注解 public class AnnotationTest2 { @MyAnnotation(value="abc") public void execute(){ System.out.println("method"); } } 当注解中使用的属性名为value时,对其赋值时可以不指定属性的名称而直接写上属性值接口; 除了value意外的变量名都需要使用name=value的方式赋值。
//添加默认值
public @interface MyAnnotation {
String value1() default "abc";
}
//多变量使用枚举
public @interface MyAnnotation {
String value1() default "abc";
MyEnum value2() default MyEnum.Sunny;
}
enum MyEnum{
Sunny,Rainy
}
//使用自定义注解
public class AnnotationTest2 {
@MyAnnotation(value1="a", value2=MyEnum.Sunny)
public void execute(){
System.out.println("method");
}
}
//数组变量 public @interface MyAnnotation { String[] value1() default "abc"; } //使用自定义注解 public class AnnotationTest2 { @MyAnnotation(value1={"a","b"}) public void execute(){ System.out.println("method"); } }
public @interface MetaAnnotation { String value(); } //注解变量 public @interface MyAnnotation { MetaAnnotation annotationAttr() default @MetaAnnotation("xx"); } //使用自定义注解,可以认为@MetaAnnotation是MetaAnnotation的一个实例对象 @MyAnnotation(annotationAttr=@MetaAnnotation("xxxx")) public class AnnotationTest2 { public static void main(String[] args) throws Exception { if(MyMethod.class.isAnnotationPresent(AnnotationTest.class)) { AnnotationTest a = MyMethod.class.getAnnotation(AnnotationTest.class); System.out.println(a.annotationAttr().value()); } } }
设置注解的作用范围: @Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Retention 指示注释类型的注释要保留多久。 如果注释类型声明中不存在 Retention 注释,则保留策略默认为 RetentionPolicy.CLASS。 只有元注释类型直接用于注释时,Target 元注释才有效。 如果元注释类型用作另一种注释类型的成员,则无效。
七、示例
定义注解,解析注解
import java.lang.annotation.*; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) @Inherited public @interface HelloWorld { public String name()default ""; }
import java.lang.annotation.*; @Documented @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface Yts { public enum YtsType{util,entity,service,model}; public YtsType classType() default YtsType.util; }
import java.lang.reflect.*; import day25.Yts.YtsType; public class ParseAnnotation { public void parseMethod(Class clazz) throws Exception { //Object obj = clazz.getConstructor(new Class[]{}).newInstance(new Object[]{}); Object obj = clazz.newInstance(); for(Method method : clazz.getDeclaredMethods()) { HelloWorld say = method.getAnnotation(HelloWorld.class); String name = ""; if(say != null) { name = say.name(); method.invoke(obj, name); } Yts yts = (Yts)method.getAnnotation(Yts.class); if(yts != null) { if(YtsType.util.equals(yts.classType())) { System.out.println(method.getName()+" is a util method"); } else { System.out.println(method.getName()+" is a other method"); } } } } @SuppressWarnings("unchecked") public void parseType(Class clazz) throws Exception { Yts yts = (Yts) clazz.getAnnotation(Yts.class); if(yts != null) { if(YtsType.util.equals(yts.classType())) { System.out.println("this is a util class"); } else { System.out.println("this is a other class"); } } } }
import day25.Yts.YtsType; @Yts(classType=YtsType.model) public class SayHell { @HelloWorld(name = " 小明 ") @Yts public void sayHello(String name){ if(name == null || name.equals("")){ System.out.println("hello world!"); }else{ System.out.println(name + "say hello world!"); } } public static void main(String[] args)throws Exception { ParseAnnotation parse = new ParseAnnotation(); parse.parseMethod(SayHell.class); parse.parseType(SayHell.class); } }