那个公司建站好,西安互联网公司,深圳集团网站开发公司,wordpress文章导入微信目录 认识注解自定义注解元注解解析注解注解的应用场景 认识注解自定义注解
注解和反射一样#xff0c;都是用来做框架的#xff0c;我们这里学习注解的目的其实是为了以后学习框架或者做框架做铺垫的。
先来认识一下什么是注解#xff1f;Java注解是代码中的特… 目录 认识注解自定义注解元注解解析注解注解的应用场景 认识注解自定义注解
注解和反射一样都是用来做框架的我们这里学习注解的目的其实是为了以后学习框架或者做框架做铺垫的。
先来认识一下什么是注解Java注解是代码中的特殊标记比如Override、Test等作用是让其他程序根据注解信息决定怎么执行该程序。
比如Junit框架的Test注解可以用在方法上用来标记这个方法是测试方法被Test标记的方法能够被Junit框架执行。 再比如Override注解可以用在方法上用来标记这个方法是重写方法被Override注解标记的方法能够被IDEA识别进行语法检查。
注解不光可以用在方法上还可以用在类上、变量上、构造器上等位置。
上面我们说的Test注解、Overide注解是别人定义好给我们用的将来如果需要自己去开发框架就需要我们自己定义注解。
自定义注解的格式如下图所示
比如现在我们自定义一个MyTest注解,注意新建的时候不是class了而是Annotation
public interface MyTest1{String aaa();//一定要带小括号 前面的public可以不写 默认自动帮你写了boolean bbb() default true; //default true 表示默认值为true,使用时可以不赋值。String[] ccc();
}定义好MyTest注解之后我们可以使用MyTest注解在类上、方法上等位置做标记。注意使用注解时需要加符号如下
MyTest1(aaa牛魔王,ccc{HTML,Java})
public class AnnotationTest1{MyTest1(aaa铁扇公主,bbbfalse, ccc{Python,前端,Java})public void test1(){}
}注意注解的属性名如果是value的话并且只有value没有默认值使用注解时value名称可以省略。比如现在重新定义一个MyTest2注解
public interface MyTest2{String value(); //特殊属性int age() default 10;
}定义好MyTest2注解后再将MyTest2标记在类上此时value属性名可以省略代码如下
MyTest2(孙悟空) //等价于 MyTest2(value孙悟空)
MyTest1(aaa牛魔王,ccc{HTML,Java})
public class AnnotationTest1{MyTest1(aaa铁扇公主,bbbfalse, ccc{Python,前端,Java})public void test1(){}
}到这里关于定义注解的格式、以及使用注解的格式就学习完了。
那注解本质是什么呢
想要搞清楚注解本质是什么东西我们可以把注解的字节码进行反编译给AnnotationTest1类加个main运行一下会使用到的注解都编译成class再使用XJad工具对class进行反编译。经过对MyTest1注解字节码反编译我们会发现
1.MyTest1注解本质上是接口每一个注解接口都继承子Annotation接口
2.MyTest1注解中的属性本质上是抽象方法
3.MyTest1实际上是作为MyTest接口的实现类对象
4.MyTest1(aaa孙悟空,bbbfalse,ccc{Python,前端,Java})里面的属性值可以通过调用aaa()、bbb()、ccc()方法获取到。 【继续往下看再解析注解时会用到】接下来我们还需要学习几种特殊的注解
元注解
什么是元注解元注解是修饰注解的注解。这句话虽然有一点饶但是非常准确。我们看一个例子 接下来分别看一下Target注解和Retention注解有什么作用,它们都是用来修饰Test注解的元注解
Target是用来声明注解只能用在哪些位置比如类上、方法上、成员变量上等
Retention是用来声明修饰的注解保留周期比如源代码时期、字节码时期、运行时期比如我们定义MyTest3注解时使用Target注解属性值写成下面样子加上Retention则可以决定MyTest3的保留周期比如我们经常用到的Test就是保留到运行阶段的可以点进源码看一下。
//声明MyTest3注解只能用在类上和方法上
Target({ElementType.TYPE,ElementType.METHOD})
public interface MyTest3{}解析注解
通过前面的学习我们能够自己定义注解也能够把自己定义的注解标记在类上或者方法上等位置但是总感觉有点别扭给类、方法、变量等加上注解后我们也没有干什么呀
接下来我们就要做点什么。我们可以通过反射技术把类上、方法上、变量上的注解对象获取出来然后通过调用方法就可以获取注解上的属性值了。我们把获取类上、方法上、变量上等位置注解及注解属性值的过程称为解析注解。
解析注解套路如下
1.如果注解在类上先获取类的字节码对象再获取类上的注解
2.如果注解在方法上先获取方法对象再获取方法上的注解
3.如果注解在成员变量上先获取成员变量对象再获取变量上的注解
总之注解在谁身上就先获取谁再用谁获取谁身上的注解来看一个案例来演示解析注解的代码编写 按照需求要求一步一步完成
① 先定义一个MyTest4注解
//声明MyTest4注解只能用在类上和方法上
Target({ElementType.TYPE, ElementType.METHOD})
//控制使用了MyTest4注解的代码中MyTest4保留到运行时期
Retention(RetentionPolicy.RUNTIME)
public interface MyTest4{String value();double aaa() default 100;String[] bbb();
}② 定义一个类Demo
MyTest4(value蜘蛛侠,aaa99.9, bbb{至尊宝,牛马})
public class Demo{MyTest4(value孙悟空,aaa199.9, bbb{紫霞,牛夫人})public void test1(){}
}③ 写一个测试类AnnotationTest3解析Demo类上的MyTest4注解
public class AnnotationTest3{Testpublic void parseClass(){//1.先获取Class对象Class c Demo.class;//2.解析Demo类上的注解if(c.isAnnotationPresent(MyTest4.class)){//获取类上的MyTest4注解MyTest4 myTest4 (MyTest4)c.getDeclaredAnnotation(MyTest4.class);//获取MyTests4注解的属性值System.out.println(myTest4.value());System.out.println(myTest4.aaa());System.out.println(Arrays.toString(myTest4.bbb()));}}Testpublic void parseMethods() throws NoSuchMethodException {//1.先获取Class对象Class c Demo.class;//2.解析Demo类中test1方法上的注解MyTest4注解Method m c.getDeclaredMethod(test1);if(m.isAnnotationPresent(MyTest4.class)){//获取方法上的MyTest4注解MyTest4 myTest4 (MyTest4)m.getDeclaredAnnotation(MyTest4.class);//获取MyTests4注解的属性值System.out.println(myTest4.value());System.out.println(myTest4.aaa());System.out.println(Arrays.toString(myTest4.bbb()));}}
}运行测试类parseClass()的运行结果如下: parseMethods()的运行结果如下 注解的应用场景
关于注解的定义、使用、解析注解就已经学习完了。接下来我们再学习一下注解的应用场景注解是用来写框架的比如现在我们要模拟Junit写一个测试框架要求有MyTest注解的方法可以被框架执行没有MyTest注解的方法不能被框架执行。
第一步先定义一个MyTest注解
Target(ElementType.METHOD)
Retetion(RetetionPloicy.RUNTIME)
public interface MyTest{}第二步写一个测试类AnnotationTest4在类中定义几个被MyTest注解标记的方法
public class AnnotationTest4{MyTestpublic void test1(){System.out.println(test1);}MyTestpublic void test2(){System.out.println(test2);}public void test3(){System.out.println(test2);}public static void main(String[] args){AnnotationTest4 a new AnnotationTest4();//1.先获取Class对象Class c AnnotationTest4.class;//2.解析AnnotationTest4类中所有的方法对象Method[] methods c.getDeclaredMethods();for(Method m: methods){//3.判断方法上是否有MyTest注解有就执行该方法if(m.isAnnotationPresent(MyTest.class)){m.invoke(a);}}}
}运行结果:
test2
test1