注解
注解概述
注解概述
注解的作用
生成帮助文档:@author和@version
执行编译期的检查 例如:@Override
框架的配置(框架=代码+配置)
小结
- 注解用在“源码中”,作为一个“标记”。给“注解解析器”看的,告诉“注解解析器”怎样编译、运行下面的代码。
- 开发中,我们一般都是使用注解
JDK提供的三个基本的注解
@Override
:描述方法的重写.
@SuppressWarnings
:压制\忽略警告.
@Deprecated
:标记过时
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| @SuppressWarnings("all") class Fu{ public void show(){
} } class Zi extends Fu{ @Override public void show(){
} } public class Demo { public static void main(String[] args) {
@SuppressWarnings("all") int num; }
@Deprecated public static void method1(){
}
public static void method2(){
} }
|
自定义注解
自定义注解语法
1 2 3
| public @interface 注解名{ 属性 }
|
1 2 3 4 5 6 7
|
public @interface Annotation01 {
}
|
注解属性
格式
属性类型
1.基本类型
2.String
3.Class类型
4.注解类型
5. 枚举类型
6.以上类型的一维数组类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public @interface Annotation01 { int a(); double b();
String c();
Class d();
Annotation02 f(); Sex e(); int[] g(); double[] h(); String[] i(); Sex[] j(); Annotation02[] k(); }
|
使用注解并给注解属性赋值
1 2 3 4 5
| 使用注解: 如果一个注解中有属性,那么使用注解的时候一定要给注解属性赋值 如果一个注解没用属性,那么就不需要给注解属性赋值,直接使用即可 如何给注解属性赋值: @注解名(属性名=值,属性名2=值2)
|
案例演示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| public @interface MyAnnotation1 { }
public @interface MyAnnotation2 { String name(); int age(); String[] arr(); }
@MyAnnotation1 @MyAnnotation2(name="张三",age=18,arr={"itheima","itcast"}) public class Test1 { @MyAnnotation1 String str;
@MyAnnotation1 @MyAnnotation2(name="张三",age=18,arr={"itheima","itcast"}) public static void main(String[] args) {
@MyAnnotation1 @MyAnnotation2(name="张三",age=18,arr={"nbchen","zuoer"}) int num = 10; } }
|
给注解属性赋值的注意事项
- 一旦注解有属性了,使用注解的时候,属性必须有值
- 若属性类型是一维数组的时候,当数组的值只有一个的时候可以省略{}
- 如果注解中只有一个属性,并且属性名为value,那么使用注解给注解属性赋值的时候,注解属性名value可以省略
- 注解属性可以有默认值 格式:属性类型 属性名() defaul t 默认值;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| public @interface MyAnnotation1 { int a(); }
public @interface MyAnnotation2 { int[] arr(); }
public @interface MyAnnotation3 { int value(); }
public @interface MyAnnotation33 { String[] value(); }
public @interface MyAnnotation4 { int a() default 10; }
public class Test { public static void main(String[] args) {
}
@MyAnnotation4(a = 100) public static void method4(){
}
@MyAnnotation33("itheima") public static void method33(){
}
@MyAnnotation3(10) public static void method3(){
}
@MyAnnotation2(arr=10) public static void method2(){
}
@MyAnnotation1(a = 10) public static void method1(){
}
}
|
元注解
什么是元注解
定义在注解上的注解
常见的元注解
@Target:表示该注解作用在什么上面(位置),默认注解可以在任何位置. 值为:ElementType的枚举值
METHOD
:方法
TYPE
:类 接口
FIELD
:字段
CONSTRUCTOR
:构造方法声明
@Retention:定义该注解保留到那个代码阶段, 值为:RetentionPolicy类型,默认只在源码阶段保留
SOURCE
:只在源码上保留(默认)
CLASS
:在源码和字节码上保留
RUNTIME
:在所有的阶段都保留
.java
(源码阶段) —-编译—> .class
(字节码阶段) —-加载内存–> 运行(RUNTIME)
案例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation1 { }
@MyAnnotation1 public class Test { int num;
@MyAnnotation1 public static void main(String[] args) { String str; } }
|
注解解析
java.lang.reflect.AnnotatedElement接口: Class、Method、Field、Constructor等实现了AnnotatedElement
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyAnnotation1 { String name();
int age();
}
public class Test {
@MyAnnotation1(name="张三",age=18) public void show1(){ System.out.println("show1方法执行了...."); }
public void show2(){ System.out.println("show2方法执行了...."); }
public static void main(String[] args) throws Exception{
Class<?> c = Class.forName("com.itheima.demo12_注解解析.Test");
Method show1M = c.getDeclaredMethod("show1");
MyAnnotation1 a1 = show1M.getAnnotation(MyAnnotation1.class); System.out.println(a1.name()); System.out.println(a1.age());
System.out.println("======================");
boolean res1 = show1M.isAnnotationPresent(MyAnnotation1.class); System.out.println(res1);
Method show2M = c.getDeclaredMethod("show2"); boolean res2 = show2M.isAnnotationPresent(MyAnnotation1.class); System.out.println(res2);
} }
|
完成注解的MyTest案例
需求
在一个类(测试类,TestDemo)中有三个方法,其中两个方法上有@MyTest,另一个没有.还有一个主测试类(MainTest)中有一个main方法. 在main方法中,让TestDemo类中含有@MyTest方法执行. 自定义@MyTest, 模拟单元测试.
思路分析
定义两个类和一个注解
在MainTest的main()方法里面:
1 2 3 4
| //1.获得TestDemo字节码对象 //2.反射获得TestDemo里面的所有的方法 //3.遍历方法对象的数组. 判断是否有@MyTest(isAnnotationPresent) //4.有就执行(method.invoke())
|
代码实现
1 2 3 4 5
| @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface MyTest {
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class TestDemo { @MyTest public void show1(){ System.out.println("show1方法执行了..."); }
@MyTest public void show2(){ System.out.println("show2方法执行了..."); }
public void show3(){ System.out.println("show3方法执行了..."); }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class MainTest {
public static void main(String[] args) throws Exception { Class<TestDemo> clazz = TestDemo.class;
Method[] methods = clazz.getDeclaredMethods();
for (Method method : methods) { boolean res = method.isAnnotationPresent(MyTest.class); if (res) { method.invoke(clazz.newInstance()); } }
}
}
|