元注解:
@Document :标记注解,注解信息包含到说明文档中
@Target:标识注解的目标:该注解用于方法、类、变量,可以有多个,类型为ElementType
TYPE:表示类、接口、枚举声明
FIELD:字段,包括枚举变量
METHOD:方法
PARAMETER:方法中的参数
CONSTRUCOTOR:构造方法
LOCAL_VARIABLE:本地变量
MODULE:模块,Java9引入的
例如:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention:标识注解信息保留到什么时候,取值只能有一个,类型为RetentionPolicy,如果不声明,默认为CLASS
SOURCE:只在源码中保留,编译为字节码文件就会丢掉
CLASS:保留到字节码文件中,但虚拟机加class文件加载到内存时不一定会在内存中保留
RUNTIME:一直保留到运行时
@Inherited : 表示注解可以继承
注解可以定义参数,定义方式:在注解内定义一些方法,返回值表示参数类型,方法名为value,且只有一个参数时可以省略“value=”
要求:
1、注解内参数只能为:基本类型、String、Class、枚举、注解
2、可以在方法末尾加上默认值:default xxx,得是具体值,不能为null
案例 1:
import java.lang.annotation.*;
public class InheritDemo {
@Inherited //注解可以继承
@Target(value = ElementType.TYPE) //注解用于类上,因为只有一个参数,可以省略 “value=”
@Retention(RetentionPolicy.RUNTIME)
static @interface Test{
}
@Test
static class Base{
}
static class Child extends Base { //继承注解
}
public static void main(String[] args) throws ClassNotFoundException {
//判断Child目前有无Test.class注解,如果改为Class或者Source,就会返回false,因为运行时没有保留
System.out.println(Class.forName(Child.class.getName()).isAnnotationPresent(Test.class));
}
}
注解原理:
Annotation是一个接口,它表示注解。注解内部实现时,都是扩展的Annotation,annotationType()方法返回实际的注解
public interface Annotation {
boolean equals(Object obj);
int hashCode();
String toString();
//返回真正的注解类型
Class<? extends Annotation> annotationType();
}
通过 public Annotation[][] getParameterAnnotations()返回方法参数的注解,每个参数对应一个一维数组。
DI案例:定义业务1和业务2,业务1依赖业务2,通过注解,把实例化交给容器实现。
//定义业务1
public class ServiceA {
@SimpleInject
private ServiceB serviceB;
public void callB(){
serviceB.action();
}
}
//定义业务B
public class ServiceB {
public void action(){
System.out.println("i am b ,do action");
}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//定义DI注解
@Target({ElementType.TYPE,ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleInject {
}
/**
* DI工厂
*/
public class SimpleContainer {
public static <T> T getInstance(Class<T> clazz){
try{
//工厂获取所需实例
T obj = clazz.newInstance();
//获取需要注入实例的成员变量
Field[] fields = clazz.getDeclaredFields();
//循环给所有需要注入的成员变量赋值
for (Field field : fields){
//如果标注有注解的成员变量,进行注入
if (field.isAnnotationPresent(SimpleInject.class)){
//如果是私有变量,设置允许获取私有变量
if (!field.isAccessible()){
field.setAccessible(true);
}
//获取私有变量的Class对象
Class<?> fieldClazz = field.getType();
//给我们需要的类注入获取到的成员对象的实例
field.set(obj,getInstance(fieldClazz));
}
}
//返回注入好的实例
return obj;
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
总结:
注解提高了Java语言的表达能力,有效实现了应用功能和底层功能的分离.业务和框架开发相分离,业务通过注解和库和框架写作