注解
转载于: https://blog.csdn.net/h294590501/article/details/80739985
注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,
注解的作用:
1.给程序带入参数
2.取代一些属性文件文件
标记可以加在包、类,属性、方法,方法的参数以及局部变量上定义。
注解的应用场景
1. 重写父类方法时。
2. 运行一个无main的方法时,带有@Test的成员方法可以直接运行,无需main方法。
3. 框架中的配置。
现在框架都是基于注解的配置,简单方便。
常见注解
JDK中内置了很多注解,以下例举一些:
1. @author:用来标识作者名。
2. @version:用于标识对象的版本号,适用范围:文件、类、方法。
3. @Override :用来修饰方法声明,告诉编译器该方法是重写父类中的方法,
如果父类不存在该方法,则编译失败
自定义注解
//定义格式
public @interface 注解名{
属性类型 属性名();
}
如:定义一个名为Book的注解
public @interface Book{
String value();
}
注解的属性
1. 属性的作用
可以让用户在使用注解时传递参数,让注解的功能更加强大。
2. 属性的格式
格式1:数据类型 属性名();
格式2:数据类型 属性名() default 默认值;
3. 属性定义示例
public @interface Student {
String value();
int age() default 44;
}
自定义注解的属性类型:
1.八种基本数据类型(int,float,boolean,byte,double,char,long,short)
2.String 类型
3.枚举类型
4.注解类型
5.以上数据类型的一维数组类型
使用自定义注解
//使用注意事项
如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。
如果属性有默认值,则使用注解的时候,这个属性如果赋值了,以赋值为准。
如果属性没有默认值,那么在使用注解时一定要给属性赋值。
默认情况下,一个注解是可以用在一个类的任意地方的。
比如说: 类上、方法上、形参上 . 如果需要限定注解的使用范围,那么需要使用上@target这个注解。
默认情况下注解的内容也只是保留到了源码上,一旦经过编译之后,注解的内容就消失了,并没有保留到class文件上。想要获取到注解的数据就必须要Runtime这种保留策略.
一个特殊的注解属性value
1. 当注解中只有一个属性且名称是value,在使用注解时给value属性赋值可以直接给
属性值,无论value是单值元素还是数组类型。
2. 如果注解中除了value属性还有其他属性,且至少有一个属性没有默认值,则在使
用注解给属性赋值时,value属性名不能省略
元注解
用来定义注解的注解。
元注解的作用
用来说明自定义注解的在类中出现的位置和生命周期。
常用元注解
@Target
作用:定义该注解用在哪个位置,如果不写,默认是类中任何地方都可以使用。
可选的参数值在枚举类ElemenetType中包括:
TYPE: 用在类,接口上
FIELD:用在成员变量上
METHOD: 用在方法上
PARAMETER:用在参数上
CONSTRUCTOR:用在构造方法上
LOCAL_VARIABLE:用在局部变量上
@Retention
作用:定义该注解的生命周期。
可选的参数值在枚举类型RetentionPolicy中包括:
SOURCE:注解只存在于Java源代码中,编译生成的字节码文件中就不存在了。
CLASS:注解存在于Java源代码、编译以后的字节码文件中,运行的时候内存中没有,这个是默认值。
RUNTIME:注解存在于Java源代码中、编译以后的字节码文件中、运行时内存中,程序可以通过反射获取该注解。
@Retention(value=RetentionPolicy.RUNTIME)//定义注解生命周期。
@Target(value={ElementType.FIELD,ElementType.METHOD})//定义注解使用位置。
public @interface Book {
int id() default 88;//图书编号
String author() default "小飞";//作者
double price() default 88.88;//单价
}
解析注解
通过Java技术,在程序运行时,获取注解中所有属性的过程则称为解析注解。
与注解解析相关的接口
Anontation:所有注解类型的公共接口,类似所有类的父类是Object。
AnnotatedElement:定义了与注解解析相关的方法,
常用方法以下四个:
1. boolean isAnnotationPresent(Class annotationClass);
判断当前对象是否有指定的注解,有则返回true,否则返回false。
2. T getAnnotation(Class<T> annotationClass);
获得当前对象上指定的注解对象。
3. Annotation[] getAnnotations();
获得当前对象及其从父类上继承的所有的注解对象。
4. Annotation[] getDeclaredAnnotations();
获得当前对象上所有的注解对象,不包括父类的。
获取注解对象
注解作用在那个成员上,就通过反射获得该成员的对象来得到它的注解。
//获取类的Class对象
Class clazz = 类名.class;
//获取private的id属性对象
Field f = clazz.getDeclaredField("id");
f.setAccessible(true);
//获取属性对象上是否有注解
flag= f.isAnnotationPresent(Book.class);
//从属性对象上获取注解Book
book = f.getAnnotation(Book.class);
如注解作用在方法上,就通过方法(Method)对象得到它的注解
//获取类的Class对象
Class clazz = 类名.class;
// 得到方法对象
Method method = clazz.getDeclaredMethod("方法名",参数类型.class);
// 根据注解名得到方法上的注解对象
Book book = method.getAnnotation(Book.class);
如注解作用在类上,就通过Class对象得到它的注解
// 获得Class对象
Class c = 类名.class;
// 根据注解的Class获得使用在类上的注解对象
Book book = c.getAnnotation(Book.class);
获取注解对象上的数据
注解对象.注解属性名();
book.price();
使用反射获取注解的数据
@Retention(value = RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD,ElementType.FIELD})
@interface Book {
String value() default "book";
String author() default "小芸";//作者
double price() default 11.11;//单价
}
public class Demo {
@Book(value="book001",author="李白",price=88)
private int id;
@Book(value="book002",author="诗仙",price=88)
public void buy() throws Exception{
//获取Test09的Class对象
Class clazz = Demo.class;
//获取public的buy方法
Method m = clazz.getMethod("buy");
//获取方法上是否有注解
boolean flag = m.isAnnotationPresent(Book.class);
//从方法上获取注解Book
Book book = m.getAnnotation(Book.class);
//获取注解Book中的所有属性了
System.out.println(book.value());
System.out.println(book.author());
System.out.println(book.price());
//上述代码叫反射注解
//获取private的id属性对象
Field f = clazz.getDeclaredField("id");
f.setAccessible(true);
//获取属性对象上是否有注解
flag= f.isAnnotationPresent(Book.class);
//从属性对象上获取注解Book
book = f.getAnnotation(Book.class);
//获取注解Book中的所有属性了
System.out.println(book.value());
System.out.println(book.author());
System.out.println(book.price());
}
public static void main(String[] args) throws Exception {
Demo test = new Demo();
test.buy();
}
}
模拟JUnit测试的@Test注释
public class Demo {
public static void main(String[] args) throws Exception{
//获取MyTestDemo类的Class对象
Class clazz = MyTestDemo.class;
//创建对象
Object obj = clazz.newInstance();
//获取public的方法
Method[] ms = clazz.getMethods();
//迭代
for (Method m : ms) {
//判断是否在运行时,看到方法上的注解@MyTest
boolean flag = m.isAnnotationPresent(MyTest.class);
//如果在运行时可见
if(flag){
//执行这个方法
m.invoke(obj,null);
}
}
}
}
/**
* @MyTest注解
*/
@Retention(value= RetentionPolicy.RUNTIME)
@Target(value= ElementType.METHOD)
public @interface MyTest {
}
/**
* 使用MyTest注解
*/
public class MyTestDemo {
@MyTest
public void test1(){
System.out.println("public void test1()");
}
public void test2(){
System.out.println("public void test2()");
}
@MyTest
public void test3(){
System.out.println("public void test3()");
}
}