1、注解基础
注解的主要作用:
- 生成文档,通过代码里标识的元数据生成javadoc文档。
- 编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
- 编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
- 运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例。
Java注解分类:
- 标准注解(Java自带),包括@Override、@Deprecated和@SuppressWarnings,分别用于标明重写某个方法、标明某个类或方法过时、标明要忽略的警告,用这些注解标明后编译器就会进行检查。
- 元注解,元注解是用于定义注解的注解,包括@Retention、@Target、@Inherited、@Documented,@Retention用于标明注解被保留的阶段,@Target用于标明注解使用的范围,@Inherited用于标明注解可继承,@Documented用于标明是否生成javadoc文档。
- 自定义注解,可以根据自己的需求定义注解,并可用元注解对自定义注解进行注解。
2、标准注解
package cn.boo.test;
/**
* @author byh
*/
public class Service implements IService{
@Override // 重写时
public void Test() {
System.out.println("测试重写");
}
@Deprecated // 废弃方法
public void delete(){
System.out.println("废弃方法");
}
public static void main(String[] args) {
new Service().delete();
}
}
- @Override:表示当前的方法定义将覆盖父类中的方法
- @Deprecated:表示代码被弃用,如果使用了被@Deprecated注解的代码则编译器将发出警告
- @SuppressWarnings:表示关闭编译器警告信息
@Override
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
@SuppressWarnings
@Target({TYPE, FIELD, METHOD, PARAMETER,CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
3、Java元注解
3.1、@Target
Target 注解的作用是:描述注解的使用范围(即:被修饰的注解可以用在什么地方) 。
public enum ElementType {
TYPE, // 类、接口、枚举类
FIELD, // 成员变量(包括:枚举常量)
METHOD, // 成员方法
PARAMETER, // 方法参数
CONSTRUCTOR, // 构造方法
LOCAL_VARIABLE, // 局部变量
ANNOTATION_TYPE, // 注解类
PACKAGE, // 可用于修饰:包
/**
* Type parameter declaration
*
* @since 1.8 // 新增版本
*/
TYPE_PARAMETER, // 类型参数
/**
* Use of a type
*
* @since 1.8 // 新增版本
*/
TYPE_USE // 使用类型的任何地方
}
3.2、@Retention & @RetentionTarget
Reteniton 注解的作用是:描述注解保留的时间范围(即:被描述的注解在它所修饰的类中可以被保留到何时) 。
public enum RetentionPolicy {
SOURCE, // 源文件保留
CLASS, // 编译期保留,默认值
RUNTIME // 运行期保留,可通过反射去获取注解信息
}
3.3、@Documented
Documented 注解的作用是:描述在使用 javadoc 工具为类生成帮助文档时是否要保留其注解信息。
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Documented
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface TestDocAnnotation {
public String value() default "default";
}
@TestDocAnnotation("myMethodDoc")
public void testDoc() {
}
3.4、@Inherited
Inherited 注解的作用:被它修饰的 Annotation 将具有继承性。如果某个类使用了被@Inherited 修饰的 Annotation ,则其子类将自动具有该注解。
- 定义@Inherited注解
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface TestInheritedAnnotation {
String [] values();
int number();
}
- 使用这个注解
@TestInheritedAnnotation(values ={"value"}, number = 10)
public class Person {
}
class Student extends Person{
@Test
public void test(){
Class clazz = Student.class;
Annotation[] annotations = clazz.getAnnotations();
for (Annotation annotation : annotations) {
System.out.println(annotation.toString());
}
}
}
3.5、@Native (Java8)
使用 @Native 注解修饰成员变量,则表示这个变量可以被本地代码引用,常常被代码生成工具使用。对于 @Native注解不常使用
3.6、注解与反射接口
定义注解后,如何获取注解中的内容呢?反射包java.lang.reé ect下的AnnotatedElement接口提供这些方法。这里注意:只有注解被定义为RUNTIME后,该注解才能是运行时可见,当class文件被装载时被保存在class文件中的Annotation才会被虚拟机读取。
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通过反射获取了某个类的AnnotatedElement对象之后,程序就可以调用该对象的方法来访问Annotation信息。
boolean isAnnotationPresent(Class<?extendsAnnotation> annotationClass)
<T extends Annotation> TgetAnnotation(Class<T> annotationClass)
Annotation[] getAnnotations()
返回该程序元素上存在的所有注解,若没有注解,返回长度为0的数组。
<T extends Annotation> T[]getAnnotationsByType(Class<T>annotationClass)
<T extends Annotation> TgetDeclaredAnnotation(Class<T> annotationClass)
<T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass)
Annotation[] getDeclaredAnnotations()
4、自定义注解
当我们理解了解了标准注解与元注解之后,就可以进行撰写自定义注解了。
- 定义注解
package cn.boo.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author byh
* 自定义注解
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMethodAnnotation {
public String title() default "";//默认为""
public String description() default "";//默认为""
}
- 使用定义的注解
package cn.boo.annotation;
import java.io.FileNotFoundException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class TestMethodAnnotation {
@Override
@MyMethodAnnotation(title = "toStringMethod", description = "override toString method")
public String toString() {
return "Override toString method";
}
@Deprecated
@MyMethodAnnotation(title = "old static method", description = "deprecated old static method")
public static void oldMethod() {
System.out.println("old method, don't use it.");
}
@SuppressWarnings({"unchecked", "deprecation"})
@MyMethodAnnotation(title = "test method", description = "suppress warning static method")
public static void genericsTest() throws FileNotFoundException {
List l = new ArrayList();
l.add("abc");
oldMethod();
}
}
- 用反射接口获取注解信息
main方法定义在使用注解的类中进行测试
public static void main(String[] args) {
try {
// 获取所有methods
Method[] methods = TestMethodAnnotation.class.getClassLoader().loadClass(("cn.boo.annotation.TestMethodAnnotation")).getMethods();
// 遍历
for (Method method : methods) {
// 方法上是否有MyMethodAnnotation注解
if (method.isAnnotationPresent(MyMethodAnnotation.class)) {
try {
// 获取并遍历方法上的所有注解
for (Annotation anno : method.getDeclaredAnnotations()) {
System.out.println(
"Annotation in Method '"
+ method +
"' : " + anno);
}
// 获取MyMethodAnnotation对象信息
MyMethodAnnotation methodAnno = method.getAnnotation(MyMethodAnnotation.class);
System.out.println(methodAnno.title());
} catch (Throwable ex) {
ex.printStackTrace();
}
}
}
} catch (SecurityException | ClassNotFoundException e) {
e.printStackTrace();
}
}
返回信息如下代表成功
Connected to the target VM, address: '127.0.0.1:29109', transport: 'socket'
Annotation in Method 'public java.lang.String cn.boo.annotation.TestMethodAnnotation.toString()' : @cn.boo.annotation.MyMethodAnnotation(title=toStringMethod, description=override toString method)
toStringMethod
Annotation in Method 'public static void cn.boo.annotation.TestMethodAnnotation.oldMethod()' : @java.lang.Deprecated()
Annotation in Method 'public static void cn.boo.annotation.TestMethodAnnotation.oldMethod()' : @cn.boo.annotation.MyMethodAnnotation(title=old static method, description=deprecated old static method)
old static method
Annotation in Method 'public static void cn.boo.annotation.TestMethodAnnotation.genericsTest() throws java.io.FileNotFoundException' : @cn.boo.annotation.MyMethodAnnotation(title=test method, description=suppress warning static method)
test method
Disconnected from the target VM, address: '127.0.0.1:29109', transport: 'socket'Process finished with exit code 0