什么是java注解
java注解是java代码的元数据,用来声明或者配置java代码,而不影响java代码的正常的运行逻辑。java注解的本质是一种特殊类型的接口,该接口继承Annotation接口。
注解的分类
java注解分为两种类型:元注解和自定义注解。
元注解
用来注解注解的注解,主要包含四个,@Target,@Retention,@Documented,@Inherited。
@Documented
//没有任何方法,用来生成文档,javadoc Test.java
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
@Target
// 用来定义注解使用的地方
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
注解几乎可以用到java的任何地方:
public enum ElementType {
TYPE, //类,接口,或者注解上
FIELD, //字段上
METHOD, //方法上
PARAMETER, //参数上
CONSTRUCTOR, //构造函数上
LOCAL_VARIABLE, //局部变量上
ANNOTATION_TYPE, //注解上
PACKAGE, //包上
TYPE_PARAMETER //类型参数上
TYPE_USE //类型上
}
@Retention
@Retention定义了注解的保留时间
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
RetentionPolicy包括,源码,字节码还有运行时:
public enum RetentionPolicy {
//源码将在编译过后丢弃该注解,注解仅仅在源码中保留
SOURCE,
//源码能保留至字节码,即字节码中保留着注解的信息,该信息不会被jvm加载
//当注解未定义retention,默认就是class
CLASS,
//java运行期,注解依然存在,可以被反射机制获取
//例如SpringMvc中的@Controller@Autowired@RequestMapping
RUNTIME
}
@Inherited
可以让注解被继承,但这并不是真的继承,只是通过使用@Inherited,可以让子类Class对象使用getAnnotations()获取父类被@Inherited修饰的注解
@Inherited
@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface YesInherited {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoInherited {
}
@YesInherited
class Parent1{ }
class Child1 extends A{ }
@NoInherited
class Parent2{ }
class Child2 extends Parent2{ }
public class Test{
public static void main(String... args){
// 能得到注解YesInherited
Parent1 instance1=new Child1();
System.out.println(Arrays.toString(instance1.getClass().getAnnotations()));
// 不能得到注解NoInherited
Parent2 instance2 = new Child2 ();
System.out.println(Arrays.toString(instance2.getClass().getAnnotations()));
}
}
自定义注解
如下自定义一个注解@DBTable,
该注解用于修饰类,接口或者注解上,
该注解可以存活到运行期
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
String name() default "";
}
然后,我们可以按如下方式使用注解,其中name就是方法的名称。
如果注解内的方法名有一个为value,在使用该注解的时只想指定value,
此时不需要写key,即@DBTable(“MEMBER”)即可,省略value=
@DBTable(name = "MEMBER")
public class Member {
}
注解方法可以使用default xxx表明该方法的返回默认值为xxx。
返回的数据类,可以有如下6大类:
1. 所有基本类型(int,float,boolean,byte,double,char,long,short)
2. String
3. Class
4. enum
5. Annotation
6. 上述类型的数组
注意注解方法的值,必须要确定,即必须要赋一个合法默认值。
java内置注解
@Override:用于标明此方法覆盖了父类的方法,源码如下
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@Deprecated:用于标明已经过时的方法或类,源码如下
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
@SuppressWarnnings:用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告,其实现源码如下:
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
//数组可以包含如下值
deprecation:使用了不赞成使用的类或方法时的警告;
unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型;
fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
path:在类路径、源文件路径等中有不存在的路径时的警告;
serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告;
finally:任何 finally 子句不能正常完成时的警告;
all:关于以上所有情况的警告
注解与反射
java可以使用反射的方式在java程序运行时动态的获取注解信息。java用Annotation来代表注解,Annotation是一个接口,是所有注解的父类,获取java的注解,实际上是获取了一个实现该子接口的类实例,相当于内部匿名类。
AnnotatedElement可以通过反射技术获取注解信息。AnnotationElement主要代表如下元素:
Class:类的Class对象定义
Constructor:代表类的构造器定义
Field:代表类的成员变量定义
Method:代表类的方法定义
Package:代表类的包定义
下面是AnnotatedElement中相关的API方法,以上5个类都实现以下的方法:
// 获取指定类型的注解
getAnnotation(Class<A> annotationClass)
// 获取所有注解,包含继承的
getAnnotations()
// 查看指定类型的注解是否存在
isAnnotationPresent(Class<? extends Annotation> annotationClass)
// 返回直接修饰该元素的注解
getDeclaredAnnotations()