java注解入门
定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
作用分类:
①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】
②代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
——参考《百度百科》
PS:注释是给人看的,注解是给计算机看的。
JDK提供的三个注解
@Override
JDK5中,它的作用是对覆盖超类中方法的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发出错误警告,JDK6之后还可以表示实现接口的方法。
public class OverrideTest {
@Override
public String tostring() {
return "test";
}
}
@Deprecated
表示被修饰的方法已经过时。 过时的方法不建议使用, 但仍可以使用。一般被标记位过时的方法都存在不同的缺陷: 1安全问题; 2新的API取代。
public class DeprecatedDemoTest {
public static void main(String[]args) {
// 使用DeprecatedClass里声明被过时的方法
DeprecatedClass.DeprecatedMethod();
}
}
class DeprecatedClass {
@Deprecated
public static void DeprecatedMethod() {
}
}
@SuppressWarnings
表示抑制警告, 被修饰的类或方法如果存在编译警告, 将被编译器忽略
参数
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默认值]
- 修饰符:默认值public abstract , 且只能是public abstract。
- 返回值类型: 基本类型、 字符串String、Class、 注解、 枚举, 以及以上类型的一维数组
- 属性名:自定义
- default默认值:可以省略
案例
自定义注解@Annotation1
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")
- 如果属性名为 value, 且当前只有一个属性, value 可以省略,例如:
@Annotation1("Switch")
。
- 如果属性名为 value, 且当前只有一个属性, value 可以省略,例如:
如果使用多个属性时, 属性名名称为 value的不能省略
如果属性类型为数组, 设置内容格式为:
{ 1,2,3 }
。 例如:names = {"Switch","Kity"}
如果属性类型为数组, 值只有一个
{ }
可以省略的。 例如:names = "Switch"
一个对象上, 注解只能使用一次,不能重复使用。
元注解
元注解:用于修饰注解的注解。(用于修饰自定义注解的JDK提供的注解)
JDK提供4种元注解:@Retention
,@Target
,@Documented
,@Inherited
@Retention用于确定被修饰的自定义注解生命周期
编译器的处理有三种策略:
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;
}
@Target用于确定被修饰的自定义注解的使用位置
编译器的修饰位置有八种:
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;
}
@Documented
使用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
如果父类使用被修饰的注解,子类是否继承。
// 让它允许继承,可作用到子类
@Inherited
public @interface Greeting {
// 使用枚举类型
public enum FontColor {
BLUE,RED,GREEN
};
String name();
FontColor fontColor() default FontColor.RED;
}
自定义注解解析AnnotatedElement
如果给类、方法等添加注解,如果需要获得注解上设置的数据, 那么就必须对注解进行解析,JDK提供了java.lang.reflect.AnnotatedElement
接口允许在运行时通过反射获得注解。
常用方法
boolean isAnnotationPresent(Class annotationClass)
当前对象是否有注解T getAnnotation(Class<T> annotationClass)
获得当前对象上指定的注解Annotation[] getAnnotations()
获得当前对象及其从父类上继承的,所有的注解Annotation[] getDeclaredAnnotations()
获得当前对象上所有的注解
Class<TestAnnotation> 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);
}
}
案例:模拟JUnit,@Test注解
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 {
}
TestAnnotation
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<TestAnnotation> 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");
}
}