动态特性 ---注解
注解:
提示:本文属于基础语法和例子,个人复习整理,用于备忘,谢谢!!!!
简介:
注解就是给程序添加一个字符@开头的标记,可以标记接口,类,方法、字段,方法参数,构造方法等。注解可以被编译器、程序运行时和其它工具使用,用于增加或修改程序行为等。
元注解:
(1)@Target:
注解的目标
属性(枚举类 ) | 说明 |
---|---|
ElementType.TYPE | 表示类、接口(包括注解),或者枚举说明 |
ElementType.FIELD | 字段,包括枚举常量 |
ElementType.METHOD | 方法 |
ElementType .PARAMETER | 方法中的参数 |
ElementType.CONSTRUCTOR | 构造方法 |
ElementType .LOCAL_VARIABLE | 本地变量 |
ElementType.MODULE | 模块(Java 9 引入) |
(2)@Retenion:
保留范围,如果没有声明@Retention,则默认为时Class
属性(枚举类) | 说明 |
---|---|
RetentionPolicy.SOURCE | 只在源码总中保留,编译器编译后就会丢掉 |
RetentionPolicy. CLASS | 保存到字节码文件中,但Java虚拟机将class文件加载到内存不一定会在内存中保留 |
RetentionPolicy.RUNTIME | 一直保留到运行时 |
(3) @Documented:
表示注解信息包含到生成的文档中。
(4)@Inherited:
继承注解,表示子类继承父类的时候也会把父类带有@Inherited元注解声明的自定义注解给继承下来。
示例:
/**
* 自定义注解
* @Target 表示注解用于的目标,可以多个,ElementType是枚举,主要可选值有:
* .TYPE: 表示类、接口(包括注解),或者枚举声明
* .FIELD: 字段,包括枚举常量
* .METHOD: 方法
* .PARAMETER: 方法中的参数;
* .CONSTRUCTOR: 构造方法
* .LOCAL_VARIABLE:本地变量
* .MODULE: 模块(Java 9引入的)
*
* @Retention 表示注解信息保留到什么时候,取值只能一个,类型为RetentionPolicy,是一个枚举,可选值有:
* .SOURCE:只在源代码中保留,编译器将代码编译为字节码文件后就会丢掉
* .CLASS:保留到字节码文件中,但Java虚拟机将class文件加载到内存时不一定会在内存中保留
* .RUNTIME:一直保留到运行时
* 如果没有Retention,则默认为CLASS
*
* @Documented 表示注解信息包含到生成的文档中
*
* @Inherited 表示继承的元注解,当这个注解加上时,加到某个类上时,这个注解类的子类会继承父类的注解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MineCustomize{
String name() default "";
}
查看注解信息:
反射中和注解相关的方法如下:
方法 | 返回值 | 说明 |
---|---|---|
getAnnotations() | Annotation [] | 获取所有注解 |
getDeclaredAnnotations() | Annotation [] | 获取所有本元素上直接声明的元素,忽略@Inherited 来的 |
getAnnotation(Class annotationClass) | A | 获取指定类型的注解,没有返回null |
isAnnotationPresent(Class<? extends Annotation>) | boolean | 判断是否有指定注解 |
注解应用示例:简易DI容器
/**
* 表示依赖关系的注解
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleInject {
}
/**
* 标记类为单列类
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface SimpleSingleton {
}
package annotation;
import java.lang.reflect.Field;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* 注解和反射来做一个简单的DI容器
*/
public class AnnoDiContaniner {
//静态注册表
private static Map<Class<?>,Object> instances = new ConcurrentHashMap<>();
//获取实例
public static <T> T getInstance(Class<T> cls){
Object obj = null;
try{
//判断该对象是否有有单例注解
Boolean simpleSingleton = cls.isAnnotationPresent(SimpleSingleton.class);
//如果没有单例注解则直接创建新对象
if(!simpleSingleton){
return createInstance(cls);
}
//从静态单例注册表里取对象
obj = instances.get(cls);
//如果取的对象不为null,直接返回
if(obj != null){
return (T) obj;
}
synchronized (cls){
//如果对象为空,生成新对象,并放入注册表里
if(obj == null){
obj = createInstance(cls);
instances.put(cls,obj);
}
}
}catch (Exception e){
e.printStackTrace();
}
return (T)obj;
}
//创建实例
public static <T> T createInstance(Class<T> cls) throws Exception{
//创建对象
T obj = cls.newInstance();
//获取该类的所有属性
Field [] fields = cls.getDeclaredFields();
for (Field field:fields) {
//判断该属性上是否包含依赖注解
if(field.isAnnotationPresent(SimpleInject.class)){
//判断该属性是否有读写权限
if(!field.isAccessible()){
//设置属性的读写权限为true
field.setAccessible(true);
}
//获取属性类型
Class<?> fieldCls = field.getType();
//设置属性值
field.set(obj,getInstance(fieldCls));
}
}
return obj;
}
static class ServiceA{
@SimpleInject
private ServiceB serviceB;
public void callB(){
serviceB.action();
}
}
@SimpleSingleton
static class ServiceB{
public void action(){
System.out.println(" I'm B");
}
}
public static void main(String[] args) {
ServiceA serviceA = getInstance(ServiceA.class);
serviceA.callB();
}
}
总结:
注解提升了Java 语言的表达能力,有效的实现了应用功能和底层功能的分离,框架/库的程序员可以专注于底层实现,借助注解实现通用的功能。