JAVA 注解
一、注解是什么?
官方概念:java支持在源文件中嵌入补充信息,这类信息被称为注解,也被称为元数据。
个人理解:注解,就是标记。
二、注解有什么用?
1.用过spring的人我想天天都在用@Controller、@Autowrite、@Service 等等注解,这些注解的作用实际上只是标记而已。
如:框架启动时,main方法中跑一套初始化动作,遍历一遍所有的类,取出带有@Service注解的类,进行实例化,将实例化后的对象装入容器中,再遍历出所有带有@Autowrite注释的属性,将该属性的类型所对应的对象赋值给该属性,这就实现了依赖注入的特性,一切都是反射的功劳。
2.还有,很多人都用过一个叫lombok的工具,以@Getter @Setter 注解自动生成getter/setter 方法,这可不是程序能干的活,生成源代码的事情只有编译器才能做,这就是注解的第二种用法,在编译中使用,而不是在运行中使用。
三、内置注解
注解接口 | 应用场合 | 作用 |
@Deprecated | 全部 | 将注解内容标记为过时 |
@Override | 方法 | 方法重写 |
@Resource | 类、接口 | 标记为要在其他地方要用到的资源 |
@Resource | 属性、方法 | 注入 |
@FunctionalInterface | 接口 | 标记为函数式接口 |
@Target | 注解(只能在注解上使用的注解叫做 元注解) | 表示该注解可以在哪里使用 详细枚举有点多 不细说 点进源码一目了然 |
@Retention | 注解 | 保留策略 |
保留策略 :3个枚举(SOURCE 、CLASS 、RUNTIME) SOURCE在编译期间丢弃 CLASS编译时保存在.class文件中 但是会被JVM丢弃 RUNTIME在运行中依旧保留可以被反射机制发现
还有一些@Documented、@Inherited、@PostConstruct、@PreDestroy等等冷门注解,个人认为没必要特别关注。
四、注解声明
官方概念分了好几个类型 说的词一套一套的高深莫测,但实际上就下面这几种声明
public @ interface Controller { }
//裸注解 直接@Controller使用
public @ interface Annot { String name();
int sex() default 1;//默认值 }
//带参数的注解需要传参数 @Annot(name="aaaaa") @Annot(name="aaaaa",sex="2")
public @ interface Mapper { String value();//value是特殊名字 }
//之所以value()是特殊名字,是因为它既可以@Mapper(value = "aaaaa") 用 也可以 @Mapper("aaaaa")用
以上只是示例声明的写法 而正常的注解都会在头上加两个元注解
@Target(ElementType.METHOD)//只能在方法上应用 @Retention(RetentionPolicy.RUNTIME)//保留策略选择运行中 public @ interface Mapper { String value();//value是特殊名字 }
五、注解使用(反射使用)
因为注解可以用在类头上,属性头上,方法头上,参数头上,写法都是用反射,非常相似,写出来不免有点多又重复,我自己看的时候也会觉得无趣
所以为避免拉低博客水准,这里只示例两个,全部示例请查看源码分享
try { Class cla = Class.forName("TestController"); if (cla.isAnnotationPresent(Controller.class)) { System.out.println("TestController类含有Controller注解"); } } catch (Exception e) { e.printStackTrace(); }
try { Class cla = Class.forName("TestController"); Method[] methods = cla.getDeclaredMethods(); Arrays.stream(methods).forEach((v) -> { Parameter[] parameters = v.getParameters(); Arrays.stream(parameters).filter((a)->a.isAnnotationPresent(Param.class)).forEach((aa)->{ Annotation annotation = aa.getAnnotation(Param.class); System.out.println(v.getName() + "方法的" + aa.getName() + "参数有Param注解 值是" + ((Param) annotation).value()); //注明一点 aa.getName() 所得到的名称实际上是arg0、arg1一类的 原因是编译器在编译的时候将参数名称替换成了arg+index格式 }); }); } catch (Exception e) { e.printStackTrace(); }
六、注解使用(编译使用)
研究中 待补充
七、源码分享