/***
* .::::.
* .::::::::.
* :::::::::::
* ..:::::::::::'
* '::::::::::::'
* .::::::::::
* '::::::::::::::..
* ..::::::::::::.
* ``::::::::::::::::
* ::::``:::::::::' .:::.
* ::::' ':::::' .::::::::.
* .::::' :::: .:::::::'::::.
* .:::' ::::: .:::::::::' ':::::.
* .::' :::::.:::::::::' ':::::.
* .::' ::::::::::::::' ``::::.
* ...::: ::::::::::::' ``::.
* ````':. ':::::::::' ::::..
* '.:::::' ':'````..
*/
public class AnnotationTest {
/*注解:诞生于JDK 5
是一个特殊的接口,用于声明一些信息,他不会对修饰的结构直接产生任何实质的影响
通常配合反射使用
还有一些注解可以更好的检测代码结构是否符合要求
如函数式接口注解:@FunctionalInterface
被此注解修饰的接口如果不是一个标准的函数式接口格式就无法通过编译
*/
/*自定义注解可以使用JDK提供的元注解修饰,限制其使用方式
* JDK提供了四个元注解
* @Target:用于限制注解的使用位置
* 可用属性:ElementType[] value(该类中提供了用于规定注解使用位置的选项)
* TYPE:类,接口,枚举类
Field:成员变量
Method:方法
PARAMETER:方法形参
CONSTRUCTOR:构造器
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解类型
PACKAGE:包
TYPE_PARAMETER:引用类型参数
@Retention:用于规定注解的生命周期
可用属性:RetentionPolicy value(该类提供了规定注解生命周期的选项)
SOURCE:注解直接在编译时被丢弃
CLASS:注解被保留在生成的CLASS文件中,但在运行时被JVM丢弃
RUNTIME:始终保留,他可以被反射获取到
@Documented:用于将注解在被javadoc解析时保留下来
@Inherited:用于将注解设置为修饰的类或接口的子结构也继承此注解
*
*
*自定义一个注解,如下
* */
/*用于在初始化对象后为其中的属性赋值*/
@Target({ElementType.FIELD,ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@interface Value{
/*基本数据类型和String
* 注解中value()方法为默认参数,可以在声明时不加名称
* 前提是其他方法有默认值*/
String value();
/*引用数据类型,全限定名称*/
String fullName() default "";
}
/*在初始化时为属性赋值*/
@Value("10")
int num;
@Test
void test() throws Exception {
Class<AnnotationTest> c = AnnotationTest.class;
AnnotationTest at = c.getConstructor().newInstance();
/*注意,不是public的结构 getField()是获取不到的*/
Field f = c.getDeclaredField("num");
Value v = f.getAnnotation(Value.class);
/*如果Value是null的话那就证明此属性没有被此注解修饰
* 就不需要再执行下面的逻辑了*/
if(v == null){
return;
}
/*基本数据类型在这里可以用switch结构判断具体类型,然后用包装类转换类型赋值
* 引用数据类型就再通过反射构建一个该类型的实例
* 这里就省略了。。。*/
f.set(at,Integer.parseInt(v.value()));
System.out.println(at.num);
/*这也差不多是Spring中依赖注入的一个模拟实现了吧*/
}
}