定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用分类:
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
②代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
——参考《百度百科》
PS:注释是给人看的,注解是给计算机看的。
JDK5中,它的作用是对覆盖超类中方法的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发出错误警告,JDK6之后还可以表示实现接口的方法。
public class OverrideTest {
@Override
public String tostring() {
return "test";
}
}
表示被修饰的方法已经过时。 过时的方法不建议使用, 但仍可以使用。一般被标记位过时的方法都存在不同的缺陷: 1安全问题; 2新的API取代。
public class DeprecatedDemoTest {
public static void main(String[]args) {
// 使用DeprecatedClass里声明被过时的方法
DeprecatedClass.DeprecatedMethod();
}
}
class DeprecatedClass {
@Deprecated
public static void DeprecatedMethod() {
}
}
表示抑制警告, 被修饰的类或方法如果存在编译警告, 将被编译器忽略
deprecation , 忽略过时
rawtypes , 忽略类型安全
unused , 忽略不使用
unchecked , 忽略安全检查
null, 忽略空指针
all, 忽略所有
import java.util.ArrayList;
import java.util.List;
public class SuppressWarningsDemoTest {
public static Listlist = newArrayList();
@SuppressWarnings("unchecked")
public void add(Stringdata) {
list.add(data);
}
}
public @interface Annotation1 {
属性1;
属性2;
......
}
修饰符 返回值类型 属性名() [default默认值]
package com.pc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Annotation1 {
// 基本类型,默认值为1
int basic() default 1;
// String类型,默认值为"string"
String str() default "string";
// Class类型
Class> clazz();
// 枚举类型
Sex sex();
// 注解类型
MyTest test();
// 数组类型
String[] name();
}
package com.pc.annotation;
public enum Sex {
Man, Woman
}
package com.pc.annotation;
/**
* 测试Annotation
*
* @author Switch
* @data 2016年10月25日
* @version V1.0
*/
public class TestAnnotation {
@Annotation1(basic = 2, clazz = TestAnnotation.class, sex = Sex.Man, test = @MyTest, name = { "zs", "ls" })
public void test1() {
}
}
注解可以没有属性, 如果有属性需要使用小括号括住。 例如: @Annotation1
或 @Annotation1()
属性格式: 属性名=属性值, 多个属性使用逗号分隔。 例如: @Annotation1(username="Switch")
@Annotation1("Switch")
。如果使用多个属性时, 属性名名称为 value的不能省略
如果属性类型为数组, 设置内容格式为: { 1,2,3 }
。 例如: names = {"Switch","Kity"}
如果属性类型为数组, 值只有一个{ }
可以省略的。 例如: names = "Switch"
一个对象上, 注解只能使用一次,不能重复使用。
元注解:用于修饰注解的注解。(用于修饰自定义注解的JDK提供的注解)
JDK提供4种元注解:@Retention
,@Target
,@Documented
,@Inherited
编译器的处理有三种策略:
RetentionPolicy.SOURCE
被修饰的注解只能存在源码中,字节码class没有。用途:提供给编译器使用。RetentionPolicy.CLASS
被修饰的注解只能存在源码和字节码中,运行时内存中没有。用途:java虚拟机使用RetentionPolicy.RUNTIME
被修饰的注解存在源码、字节码、内存(运行时)。用途:取代xml配置public enum RetentionPolicy {
// 此类型会被编译器丢弃
SOURCE,
// 此类型注解会保留在class文件中,但JVM会忽略它
CLASS,
// 此类型注解会保留在class文件中,JVM会读取它
RUNTIME
}
// 让保持性策略为运行时态,即将注解编码到class文件中,让虚拟机读取
@Retention(RetentionPolicy.RUNTIME)
public @interface Greeting {
// 使用枚举类型
public enum FontColor {
BLUE,RED,GREEN
};
String name();
FontColor fontColor() default FontColor.RED;
}
编译器的修饰位置有八种:
ElementType.TYPE
修饰类 、接口ElementType.METHOD
修饰方法ElementType.FIELD
修饰字段ElementType.PARAMETER
修饰方法参数ElementType.CONSTRUCTOR
修饰构造ElementType.LOCAL_VARIABLE
修饰本地变量或catch语句ElementType.ANNOTATION_TYPE
修饰注解类型ElementType.PACKAGE
修饰java包public enum ElementType {
// 用于类,接口,枚举但不能是注解
TYPE,
// 字段上,包括枚举值
FIELD,
// 方法,不包括构造方法
METHOD,
// 方法的参数
PARAMETER,
// 构造方法
CONSTRUCTOR,
// 本地变量或catch语句
LOCAL_VARIABLE,
// 注解类型(无数据)
ANNOTATION_TYPE,
// Java包
PACKAGE
}
// 限制注解使用范围
@Target({ElementType.METHOD,ElementType.CONSTRUCTOR})
public @interface Greeting {
// 使用枚举类型
public enum FontColor {
BLUE,RED,GREEN
};
String name();
FontColor fontColor() default FontColor.RED;
}
使用javaDoc生成api文档时,是否包含此注解。
// 让它定制文档化功能
// 使用此注解时必须设置RetentionPolicy为RUNTIME
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Greeting {
// 使用枚举类型
public enum FontColor {
BLUE,RED,GREEN
};
String name();
FontColor fontColor() default FontColor.RED;
}
如果父类使用被修饰的注解,子类是否继承。
// 让它允许继承,可作用到子类
@Inherited
public @interface Greeting {
// 使用枚举类型
public enum FontColor {
BLUE,RED,GREEN
};
String name();
FontColor fontColor() default FontColor.RED;
}
如果给类、方法等添加注解,如果需要获得注解上设置的数据, 那么就必须对注解进行解析,JDK提供了java.lang.reflect.AnnotatedElement
接口允许在运行时通过反射获得注解。
boolean isAnnotationPresent(Class annotationClass)
当前对象是否有注解T getAnnotation(Class annotationClass)
获得当前对象上指定的注解Annotation[] getAnnotations()
获得当前对象及其从父类上继承的,所有的注解Annotation[] getDeclaredAnnotations()
获得当前对象上所有的注解Class clazz = TestAnnotation.class;
// 创建实例
TestAnnotation annotation = clazz.newInstance();
// 获取所有方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// 如果存在"MyTest"注解,则调用该方法
if (method.isAnnotationPresent(MyTest.class)) {
method.invoke(annotation, null);
}
}
package com.pc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
}
package com.pc.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyTest {
}
package com.pc.annotation;
import java.lang.reflect.Method;
/**
* 测试Annotation
*
* @author Switch
* @data 2016年10月25日
* @version V1.0
*/
public class TestAnnotation {
public static void main(String[] args) throws Exception {
// 模拟@Test注解
// 获取当前类的Class对象
Class clazz = TestAnnotation.class;
// 创建实例
TestAnnotation annotation = clazz.newInstance();
// 获取所有方法
Method[] methods = clazz.getMethods();
for (Method method : methods) {
// 如果存在"MyTest"注解,则调用该方法
if (method.isAnnotationPresent(MyTest.class)) {
method.invoke(annotation, null);
}
}
}
@MyTest
public void test2() {
System.out.println("test2");
}
@MyTest
public void test3() {
System.out.println("test3");
}
@MyTest
public void test4() {
System.out.println("test4");
}
}