Java 注解
注解的一般形式 :
public @interface 注解名{
属性;
}
注解的本质
-
自定义一个注解
public @interface MyAnno{}
-
通过 cmd 控制台 javac 自定义注解 生成 MyAnno.class 文件
-
通过 javap 反编译 MyAnno.class 得到:
Compiled from "MyAnno.java" public interface MyAnno extends java.lang.annotation.Annotation {}
-
由此可知,注解 的本质就是 interface ,所有的 注解都继承 java.lang.annotation.Annotation 这个类
注解的属性
-
注解中的抽象方法称为注解的属性
-
属性的要求
-
返回值必须为以下数据类型
- 基本的数据类型
- byte short int long
- float double
- boolean
- char
- String
- String []
- 枚举
- 注解
- 基本的数据类型
-
定义的属性要对属性赋值
-
例如:自定义的一个注解,里面有两个属性
public @interface MyAnno { String name() default "张三"; //属性 可以使用default指定默认值,指定默认值后使用可以无需再指定 int age(); }
-
使用时:
@MyAnno(age = 21,name = "李四") public class AnnoTest {}
必须将所有未指定默认值的属性全部赋值,形式类似于 Key—Value (这也是将注解中抽象方法称为属性的原因)
-
-
元注解
- 元注解就是描述注解的注解
- 四大元注解:
- @Target 描述注解可以作用的范围
- 属性的取值
- TYPE 可以作用再某类上
- METHOD 可以作用在某方法上
- FILED 可以作用在属性上
- 属性的取值
- @Retention 描述注解可以保留的阶段
- 属性的取值
- SOURCE 保留到源文件阶段
- CLASS 保留到字节码阶段
- RUNTIME 保留到运行时阶段
- 属性的取值
- @Documented 描述注解是否可以抽取到api文档上
- @Inherited 描述注解是否被子类继承
- @Target 描述注解可以作用的范围
注解使用实例
- 要求:不改变一个类的代码,获取类的所有属性,获取类的所有方法
- 创建自定义注解
package cn.test.anno;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnno {
String className();
String classMethod();
}
2.创建一个测试类
package cn.test.bean;
public class TestBean {
public void show() {
System.out.println("恭喜你获得到了show()方法");
}
}
- 测试注解
package cn.test.anno;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
@MyAnno(className = "cn.test.bean.TestBean", classMethod = "show")
public class TestAnno {
public static void main(String[] args) throws Exception {
// 获取本类字节码
Class clazz = TestAnno.class;
// 获取本类注释对象
MyAnno an = (MyAnno) clazz.getAnnotation(MyAnno.class);
// 获取注释值
String className = an.className();
String classMethod = an.classMethod();
// 创建测试对象字节码
Class<?> cl = Class.forName(className);
// 获取测试对象
/*
* (底层生产一个 impl 类 来实现 注解,并对注解类中方法进行重写) 例如
class MyAnnoImpl implements MyAnno {
@Override
public String className() {
return "cn.test.bean.TestBean"; //返回传入的值
}
@Override
public String classMethod() { //返回传入的值
return "show";
}
}
*/
//获取测试类对象
Object obj = cl.getConstructor().newInstance();
Method method = cl.getMethod(classMethod);
method.invoke(obj);
}
}
小结
在以后的学习中我们很少进行自定义注解,一般情况直接使用注解就行,所以注意用途:
- 一般给 编译器 用
- 一般给解析程序用
- 注解不是一个方法中的组成部分(方法没了注解仍然是方法)