女朋友:我想要我自己的注解,你教我!
moon:诶?你怎么突然想要自己的注解了?
女朋友:关你什么事!「分手」!
moon:别别别别别!我教!
moon:看好了,我的宝~,你spring学的不错,那我先带你参观下Autowired吧~
代码语言:javascript复制@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
moon:看到 「Autowired」 发现,这个类的「类名就叫 Autowired」,所以你知道为什么贴的是 @Autowired 了吗?
女朋友:哦哦哦哦哦哦!我懂了!原来「类名就是注解名」!
moon:我女朋友就是聪明!我们再来看看,它还有一点比较特殊的地方,类的标志是 class,而「注解的标志是 @interface」。
女朋友:嗯.....不错不错,你继续
moon:我们再来看下 @Autowired 上面还有三个注解,分别是什么作用,先来看第一个 「@Documented」
代码语言:javascript复制/**
* Indicates that annotations with a type are to be documented by javadoc
* and similar tools by default. This type should be used to annotate the
* declarations of types whose annotations affect the use of annotated
* elements by their clients. If a type declaration is annotated with
* Documented, its annotations become part of the public API
* of the annotated elements.
*
* @author Joshua Bloch
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}
moon:看,我们发现了,第一个是 @Documented,我们来看看它的注释是什么?
moon:通过我强大的英文阅读能力,发现 「@Documented 注解其实只是用来生成文档的」,使用 javadoc 就可以生成 api 文档了,所以这个注解,肯定「不重要」
女朋友:呸!你明明是靠翻译的!学渣!
moon:嘿嘿,我们再来看下一个!「@Retention」!这个可有的说头了
代码语言:javascript复制/**
* Indicates how long annotations with the annotated type are to
* be retained. If no Retention annotation is present on
* an annotation type declaration, the retention policy defaults to
* {@code RetentionPolicy.CLASS}.
*
* <p>A Retention meta-annotation has effect only if the
* meta-annotated type is used directly for annotation. It has no
* effect if the meta-annotated type is used as a member type in
* another annotation type.
*
* @author Joshua Bloch
* @since 1.5
* @jls 9.6.3.2 @Retention
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
moon:再次通过我强大的英文阅读能力看下,这个注释到底是什么意思?
moon:其实它就是告诉你,该注解的「生命周期」有多久,而这个生命周期的定义,「就在 RetentionPolicy 里面」,我们再来看看这个 RetentionPolicy 到底是什么?
代码语言:javascript复制public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.关注公众号:moon聊技术,获取更多有趣文章
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
女朋友:这个我熟!「SOURCE 的意思就是说被作用在源代码上,CLASS 就是被作用在编译出来的源码上,RUNTIME 就是只作用在运行时」!这不就是 Java 的三种状态嘛!
moon:你都学会抢答了我的宝!!!!
女朋友:哼!快继续!!
moon:哈哈哈,好的,那我们就来说说最后一个注解 「@Target」
代码语言:javascript复制@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/**
* Returns an array of the kinds of elements an annotation type
* can be applied to.
* @return an array of the kinds of elements an annotation type
* can be applied to
*/
ElementType[] value();
}
moon:这个注解的作用其实很简单,「就是告诉你该注解可以被贴在哪些作用域中」,而作用域有哪些你知道吗?
女朋友:嗯...有类、方法、成员变量.....
moon:哈哈哈哈哈,不知道了吧!!
女朋友:哼!!「分手」!!!!
moon:别别别别别别,听我给你娓娓道来!这个作用域其实就藏在 「ElementType[]」 这个数组当中,我们进去看下!
代码语言:javascript复制public enum ElementType {
/** Class, interface (including annotation type), or enum declaration 关注公众号:moon聊技术,获取更多有趣文章*/
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
moon:总共有「10种作用域」
作用域 | 含义 |
---|---|
TYPE | 用于描述类、接口(包括注解类型) 或enum声明 |
FIELD | 用于描述域 |
METHOD | 用于方法 |
PARAMETER | 用于描述参数 |
CONSTRUCTOR | 用于描述构造器 |
LOCAL_VARIABLE | 用于描述局部变量 |
ANNOTATION_TYPE | 用于描述注解 |
PACKAGE | 用于描述包 |
TYPE_PARAMETER | 表示该注解能使用在自定义类型参数 |
TYPE_USE | 是对类型的注解 |
所以当你确定你注解的作用域之后,你贴上 @Target(作用域),就可以了!
女朋友:噢噢噢噢,我懂了,那我有个问题,「如果我想让我的子类也继承这个注解该怎么做呢」?
moon:!!!!!!!这就是我接下来要讲的!!「@Inherited」 !!也是 java 四大元注解之一(还有三个就是刚刚提到的@Target,@Retention,@Documented)!它的作用就是「让子类也能继承该父类的该注解」,那你知道该怎么用嘛?
女朋友:分....
moon:我来给你举个例子!正好练习一下!
女朋友:哼!
moon:我们先写个注解类
代码语言:javascript复制@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MyAnnotation {
/**
* 说我爱你(默认true)
*/
boolean sayILoveYou() default true;
}
moon:这个注解很简单,「只能作用在方法上,在运行时实现,有个 syaILoveYou 的方法,默认是true!」
女朋友:yue~快说
moon:哈哈,再定义一个我,有个 sayLoveYou()方法,贴上了我们的 @MyAnnotation 注解,表达一下我的真心
代码语言:javascript复制public class Me {
@MyAnnotation
public void sayLoveYou(){
System.out.println("表达一下我的真心");
}
}
女朋友:yue~
moon:好了,现在我们开始测试了!
代码语言:javascript复制public class Main {
public static void main(String[] args) {
try {
//获取Me的Class对象
Me me = new Me();
Class clazz = me.getClass();
//获取该对象sayLoveYou方法上Info类型的注解
MyAnnotation myAnnotation = clazz.getMethod("sayLoveYou", null).getDeclaredAnnotation(MyAnnotation.class);
if (myAnnotation.sayILoveYou()) {
System.out.println("我爱你");
} else {
System.out.println("我不爱你");
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
moon:我们先获取到了 Me 的对象,然后获取到了 MyAnnotation 这个注解,如果 myAnnotation.sayILoveYou() 为true,就会输出"我爱你"!如果为false,就会输出"我不爱你"!
女朋友:你不爱我,「我们分手」
moon:咳咳,测试测试~我们运行看下,结果一定是我爱你!因为我们默认为true
moon:我们修改下注解的默认值,结果就为我EN爱你了(满满的求生欲)
代码语言:javascript复制public class Me {
@MyAnnotation(sayILoveYou=false)
public void sayLoveYou(){
System.out.println("表达一下我的真心");
}
}
女朋友:哼~
moon:我们再试验下 @Inherited 这个注解,修改下 MyAnnotation,「添加 @Inherited」,添「加 ElementType.TYPE 并且使其可以作用在类上」
代码语言:javascript复制@Retention(RetentionPolicy.RUNTIME)
@Target({Ele,mentType.METHOD,ElementType.TYPE})
@Inherited
public @interface MyAnnotation {
/**
* 说我爱你(默认true)
*/
boolean sayILoveYou() default true;
}
moon:Me 这个类在类上贴 @MyAnnotation 注解
代码语言:javascript复制@MyAnnotation
public class Me {
public void sayLoveYou(){
System.out.println("表达一下我的真心");
}
}
moon:然后我们假如有孩子了
代码语言:javascript复制public class Child extends Me{
}
女朋友:我不会和你结婚的!
moon:哈哈哈,假设假设,我们再来重写 Main 方法
代码语言:javascript复制public static void main(String[] args) {
try {
//获取child的Class对象
Child child = new Child();
Class clazz = child.getClass();
//获取该对象sayLoveYou方法上Info类型的注解
MyAnnotation myAnnotation = (MyAnnotation) clazz.getAnnotation(MyAnnotation.class);
if (myAnnotation.sayILoveYou()) {
System.out.println("我爱你");
} else {
System.out.println("我不爱你");
}
} catch (Exception e) {
e.printStackTrace();
}
}
moon:「我们此时 child 对象是没有 @MyAnnotation 注解的,只是继承了我,但是由于我们再 Me 类贴了 @MyAnnotation 注解,并且有 @Inherited 注解,所以 child 也有该注解的功能,所以运行结果一定是我爱你!」
moon:这下你会了吧!注解就是这么简单!
女朋友:哼,你还是有点用的,我不需要你了,你走吧
moon:好的老板!(终于教会了,我又活下来了)
一共分了多少次手,你们数清楚了吗?