一.注解的概念_作用
- 例如:@Override(用在子类重写父类的方法),@FunctionInterface(定义函数式接口),@Test(JUnit的,单元测试)。
注解的作用:写在“源码中”,给“注解解析器”看的。告诉注解解析器,怎样编译、运行后面的代码。 - “注解”的本质上就是一个“类”,可以单独定义java文件,编译成class。可以自己单独定义注解。
二.自定义注解的基本格式
- 自定义注解:
public @interface MyTest {
}
- 我们的注解目前有两个问题
没有任何作用
注解可以放在任何位置
三.元注解
- “元注解”是java内部定义好的注解,专门用在"注解的定义上"
作用:他可以约束新定义的注解:
A使用位置;
b生命周期
2.示例代码
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
public @interface MyTest {
}
- 具体
A).约束新注解的"使用位置":
@Target(属性值)
可选的几个属性值(ElementType枚举):
ELementType.TYPE:类\接口
ElementType.FIELD:成员变量
ElementType.METHOD:成员方法
ElementType.PARAMENTER:方法参数
ElementType.CONSTRUCTOR:构造方法
ElementType.LOCAL_VARIABLE:局部变量
B).约束新注解的"生命周期":
@Retention(属性值)
属性值:可选的几个属性值(RetentionPolicy枚举)
1 . RetentionPolicy.SOURCE:这个枚举表示注解只存在于源码中,不会被编译到class中.给编译器中的注解解析器用的.@Override
2 . RetentionPolicy.CLASS:表示此枚举会存在于源码\class文件,但运行时不会被加载到内存.(没有例子)
3. RetentionPolicy.RUNTIME:这个枚举表示注解会存在源码\class\运行时内存.例如:Junit的@Test注解
解析注解
- 模仿Junit
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取Student的Class对象
Class aClass = Class.forName("com.itheima.注解.Student");
//2.创建对象
Object o = aClass.getConstructor().newInstance();
//3.获取Student中所有的公有的方法
Method[] methods = aClass.getMethods();
//对方法名进行解析
Arrays.sort(methods, (o1, o2) -> o1.getName().compareTo(o2.getName()));
//4.遍历数组
for (Method m : methods) {
//5.判断这个Method上是否使用了MyTest注解
if(m.isAnnotationPresent(MyTest.class)){
m.invoke(o);
}
}
}
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
public @interface MyTest {
}
@MyTest
public class Student {
@MyTest
private int name;
public Student(){
}
@MyTest
public void show2(){
System.out.println("show2");
}
@MyTest
public void show1(){
System.out.println("show1");
}
@MyTest
public void show4(){
System.out.println("show4");
}
@MyTest
public void show3(){
System.out.println("show3");
}
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
}
定义包含属性的注解
- 定义格式:
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
public @interface MyTest {
//注解中可以定义属性:格式:属性类型 属性名() [default 值];
int index() default 0;
}
- 使用
@MyTest
public class Student {
@MyTest
private int name;
public Student(){
}
@MyTest(index = 3)
public void show2(){
System.out.println("show2");
}
@MyTest(index = 4)
public void show1(){
System.out.println("show1");
}
@MyTest(index = 1)
public void show4(){
System.out.println("show4");
}
@MyTest(index = 2)
public void show3(){
System.out.println("show3");
}
public int getName() {
return name;
}
public void setName(int name) {
this.name = name;
}
}
3.注解解析器(按MyTest注解的index属性值进行排序):
public class Test01 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取Student的Class对象
Class aClass = Class.forName("com.itheima.注解.Student");
//2.创建对象
Object o = aClass.getConstructor().newInstance();
//3.获取Student中所有的公有的方法
Method[] methods = aClass.getMethods();
//对方法名进行解析
Arrays.sort(methods, (o1, o2) -> {
//按注解的属性index的值,进行排序
//1.判断两个参数Method是否都是用了MyTest注解
if (o1.isAnnotationPresent(MyTest.class) && o2.isAnnotationPresent(MyTest.class)) {
//2.取出每个方法的@MyTest注解对象
MyTest t1 = o1.getAnnotation(MyTest.class);
MyTest t2 = o2.getAnnotation(MyTest.class);
//3.取出每个注解的index属性值
int index1 = t1.index();
int index2 = t2.index();
return index1 - index2;
}
return 0;
});
//4.遍历数组
for (Method m : methods) {
//5.判断这个Method上是否使用了MyTest注解
if(m.isAnnotationPresent(MyTest.class)){
m.invoke(o);
}
}
}
}
- 其他一些问题:
1).注解的属性的数据类型:四类八种的基本数据类型\class类型\String类型\注解类型\枚举类型\以上几种的数组类型.
2).如果"注解"中只有一个属性.而且属性名叫:value,使用注解时,可以省略"属性名",直接设置值.
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
public @interface MyTest {
//注解中可以定义属性:格式:属性类型 属性名() [default 值];
int value() default 0;
}
@MyTest
public class Student {
@MyTest
private int name;
public Student() {
}
@MyTest(value = 3)
public void show2() {
System.out.println("show2");
}
@MyTest(value = 4)
public void show1() {
System.out.println("show1");
}
@MyTest(1)
public void show4() {
System.out.println("show4");
}
@MyTest(2)
public void show3() {
System.out.println("show3");
}
}