java注解
Java注解
- 注解概述
- 内置的基本注解类型
- 自定义注解类型
- 对注解进行注解
- 使用反射获取注解信息
注解概述
annotation。可以添加到程序的任何元素上,用来设置一些说明和解释,java开发和部署工具可以读取这些注释,并以某种形式处理这些注释,可生成其他java源文件、XML文档或要与包含注释的程序一起使用的其他构件。
元数据:描述数据的一种数据。
注解是代码中的特殊标记,可以再编译、类加载、运行时被读取,并执行响应的处理。
注解被用来为程序元素(类、方法、成员变量等)设置元数据,它不影响程序代码的执行,无论增加、删除注解程序的执行都不受任何的影响。
访问和处理注解的工具统称为:APT(Annotation Processing Tool)。
JDK内置的基本注解类型
采用@标记,后面根生注解类型名称,name = value的形式。
@SuppressWarnings(value={"unchecked"});
注解类型和注解的区别:注解类型是某一类型注解的定义,注解是某注解类型的具体实例。
重写Override
限定重写的方法,指明被注解的方法必须是重写超类中的方法,这个注解只能用于方法上。编译器在编译源代码时会检查用@Override标注的方法是否有重写父类的方法。
被Override注解的方法必须在父类中存在同样的方法,编译才能通过。
警告Deprecated
用来标记已过时的成员的注解类型,用来指明被注解的方法是一个过时的方法,不建议使用了。编译到Deprecated的方法的类,编译器会产生警告。
抑制警告SuppressWarnings
抑制编译器警告的注解类型,用来指明被注解的方法、边或类在编译时如果有警告信息,就阻止警告。
public class SuppressWarningsTest {
public static void main() {
List list = new ArrayList();
list.add("xx");
}
}
编译这段代码会得到警告
注意:SuppressWarningsTest使用了未经检查或不安全的操作。
注意:要了解详细新,请使用-Xlint:unchecked重新编译
List类必须使用泛型才是安全的,才能进行类型检查。
两种方法不显示警告:
public class SuppressWarningsTest {
public static void main() {
List<String> list = new ArrayList<String>();
list.add("xx");
}
}
public class SuppressWarningsTest {
@SupressWarnings("unchecked")
public static void main() {
List list = new ArrayList();
list.add("xx");
}
}
@SupressWarnings(value ={"unchecked", "deprecation"})
表示要抑制未检查和已过时警告。
自定义注解类型
注解类型的定义和接口类型的定义差不多,知识在interface前面多加了一个"@"
public @interface MyAnnotation {
String value(); //定义一个属性 也可以不定义
}
class User{
@MyAnnotation("abc") //此处的abc若没有显示指定属性名,却指定了属性值,而恰好有名为value的属性名,则隐式将值赋给value属性,若果没有value属性,就会出现编译错误。
public void method(){
}
}
也可以给属性赋默认值。
enum Status {ACTIVE, INACTIVE};
public @interface MyAnnotation {
String value(); //定义一个属性 也可以不定义
Status status() default Status.ACTIVE;
}
也可以显示指定值。
对注解进行注解
对注解类型的注解。
目标Target
ElementType枚举类型。
public enum ElementType {
Type, //适用于类、接口、枚举
FILED, //适用于成员字段
METHOD, //适用于方法
PARAMETER, //适用于方法的参数
CONSTRUCTOR, //适用于构造方法
LOCAL_VARIABLE, //适用越局部变量
ANNOTATION_TYPE, //适用于注解类型
PACAGE //适用于包
}
使用Target时至少要提供这些枚举值中的一个,以指定该被注解的注解类型可以应用于程序上的哪些元素。
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
//表示自定义这个注解类型只能作用在构造方法和成员方法上
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
@interface MethodAnnotation {
}
@MethodAnnotation //作用在类上 -->编译出错
public class TargetTest {
@MethodAnnotaion //作用在方法上 -->正确
public void myMthod(){}
}
类型Retention
要读取程序中的注解信息,首先要把注解信息留在程序中,即保存在class文件中才能被读出来。
三种方式:
- 编译器处理完,不保留注解到编译后的类文件中
- 将注解保存在编译后的类文件中,但是在运行时忽略它
- 将注解保存在编译后的类文件中,并再第一次加载类时读取它。
三种方式对应java.lang.annotation.RetentionPolicy枚举的3个值
public enum RetentionPolicy {
SOURCE, //编译器处理完,不保留注解到编译后的类文件中
CLASS, //将注解保存在编译后的类文件中,但是在运行时忽略它
RUNTIME //将注解保存在编译后的类文件中,并再第一次加载类时读取它
}
@Retention(RetentionPolicy.SOURCE)
@interface My1{}
@interface My2{}
@Retention(RetentionPolicy.RUNTIME)
@interface My3{}
My1不爆粗你在class文件中,类似java代码中的//注释,在编译成字节码时会被过滤掉。
My2使用默认值CLASS将被保存在class文件中,但在运行时会被忽略,不能被反射读取。
My3可以再运行时通过反射来读取它的信息。
Override、SupressWarnings为SOURCE,Deprecated为RUNTIME。
文档Document
注解和文档有关。
定义为Document的注解必须设置为Retention的值为RUNTIME
@Document
@Retention(RetentionPolicy.RUNTIME)
@interface DocAnnotation {
}
继承Inherited
继承注解。
父类的注解默认不能被子类继承。
要想继承需要添加Inherited注解
利用反射获取注解信息
注解必须是RUNTIME的。
java.lang.relect.AnnotatedElement接口定义了四种反射读取注解信息。
public Annotation getAnnotation(Class annotationType)
:如果存在该元素的指定类型的注解,则返回这些注解,否则返回nullpublic Annotation[] getAnnotations()
:返回此元素上存在的所有注解public Annotation[] getDeclaredAnnotations()
:返回存在于此元素上的所有注解public boolean isAnnotationPresent(Class annotationType)
:如果指定类型的直接存在于此元素上则返回true否则返回false
java.lang.Class类和java.lang.reflect包中的Constructor、Filed、Method、Package类都实现了AnnotatonElement接口。
package Annotation;
import java.lang.annotation.*;
import java.lang.reflect.Method;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnno {
String value() default "无值";// 默认值
}
@MyAnno
class UserMyanno{
@MyAnno("method")
@Deprecated
public void test() {
}
}
public class MyAnnotation {
public static void main(String[] args) throws SecurityException, NoSuchMethodException {
//获取指定类注释类的Annotation实例
Annotation anno1 = UserMyanno.class.getAnnotation(MyAnno.class);
if (anno1 != null) {
MyAnno myAnno = (MyAnno)anno1;
System.out.println("类上的MyAnno注解:value="+myAnno.value());
}
//取的test()方法的对应Method实例
Method method = UserMyanno.class.getMethod("test");
Annotation[] annotations = method.getAnnotations();
for (Annotation anno : annotations) {
System.out.println("注解类型名为:"+anno.annotationType().getName());
}
}
}