注解又称java标注,是1.5版本后引出的概念。
在说注解之前,先看一个例子,也就是常见的注解之一
class Person{
public void show() {
}
}
class Student extends Person{
@Override
public void show() {
// TODO Auto-generated method stub
super.show();
}
}
上面例子中的@override 就是一个注解,这样至少可以看出注解的一个呈现方式。
方法,属性,类,参数,甚至引入包都可以用到注解,载编译器生成类文件时,注解也会在其中。甚至java 虚拟机也可以保留注解,在运行的时候也会得到其内容,然后再运行中起到作用。
当然注解启动作用,其实本质是运用了反射。不过本章主要讲解其使用,以及自定义。等到讲解反射的时候会具体实现其原理。
当然java既然引入了注解的概念,自然也会有自己的一套注解。其常用的注解如下
共有 7 个,3 个在 java.lang 中,剩下 4 个在 java.lang.annotation 中。不过从1.7版本开始又新加入了3个注解。
- 1.7版本之前的注解
- 作用在代码的注解(在java.lang)
- @Override :检查方法是否是重新方法,如果发现父类或引用接口中没有这个方法会报错。
- @Deprecated: 标记已过的方法,如果使用这个方法会报编译警告(很多人见过,再调用的生活方法上会有一个横杠)。
- @SuppressWarnings :指示应该在注释元素(以及包含在该注释元素中的所有程序元素)中取消显示指定的编译器警告。
- 元注解:作用在注解上的注解
- @Retention: 标识这个注解如何保存,在代码中,还是编入class文件中,或者运行中通过反射访问。如果注释类型声明中不存在 Retention 注释,则保留策略默认为
RetentionPolicy.CLASS
。 - @Documented: 标记这些注解是否含在用户文档中。
- @Target:标记这些注解作用在哪里成员,比如属性,方法等
- @Inherited:标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)。注意,如果使用注释类型注释类以外的任何事物,此元注释类型都是无效的。还要注意,此元注释仅促成从超类继承注释;对已实现接口的注释无效。
- @Retention: 标识这个注解如何保存,在代码中,还是编入class文件中,或者运行中通过反射访问。如果注释类型声明中不存在 Retention 注释,则保留策略默认为
- 从java7开始,又添加了3个注解。
- @SafeVarargs: java 7 开始支持,忽略任何使用参数为泛型变量的方法或结构函数调用产生的警告。
- @FunctionalInterface :Java8开始支持,标志一个匿名函数或函数接口(java8中很重要的一个接口类,函数接口以后单独讲解一下)。
- @Repeatable: java 8,开始支持,标识注解可以在同一个声明上使用多次。
- 作用在代码的注解(在java.lang)
可以看出我们所用的注解,都是实现了Annotation这个接口,不过看其实现的类比我前面所写的多很多,其实那些是扩展类中的注解。
本章只是简单去理解和自己创建注解即可,其源码实现原理我们暂时不会翻看,毕竟其实现原理涉及到反射,而发射还没有具体讲解。
-
@Override
@Target(value=METHOD) @Retention(value=SOURCE) public @interface Override
通过过@Target 可以看出其目标主要针对的是方法,而其存在策略是在SOURCE中,也就是在在java 文件中,而不会在其生成的class 文件中存在,
-
@Deprecated
@Documented @Retention(value=RUNTIME) public @interface Deprecated
通过@Documented可以得到这个注解会存在文档中。而根据@Retention可以得到其存在策略在RUNTIME中不过这个要说RUNTIME存在策略包含SOURCE存在策略,是包含关系,其三个范围依次RUNTIME>CLASS>SOURCE.虽然用的是大于号,其实是范围包含的意思。如果@Retention的存在策略在RUNTIME中也就是在CLASS于SOURCE中都会存在。
-
@SuppressWarnings
@Target(value={TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE}) @Retention(value=SOURCE) public @interface SuppressWarnings
通过@Target可以知道这个注解可以作用于数据类型,属性,方法等上。而其存在策略是SOURCE.
-
@SafeVarargs
@Documented @Retention(value=RUNTIME) @Target(value={CONSTRUCTOR,METHOD}) public @interface SafeVarargs
因为没有使用新的元注解,自己可以看出。
-
@FunctionalInterface
@Documented @Retention(value=RUNTIME) @Target(value=TYPE) public @interface FunctionalInterface
因为没有使用新的元注解,自己可以看出。
-
@Repeatable
@Documented @Retention(value=RUNTIME) @Target(value=ANNOTATION_TYPE) public @interface Repeatable
因为没有使用新的元注解,自己可以看出。
当然注解还可以自己写注解,下面我们自己写一个注解,其实写自己的注解我们可以通过其他注解,然后模拟写一个。
当然这个可以写一个
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
public class MyAnnotation {
@myan(name="test",interest= {"testInsterest"})//只有age不写才不会报错,而且顺序无关因为参数赋值需要 参数名=参数值
@myAn1("df")
public void test() {
}
}
// 注解可以使用,目前我定义的是方法,和属性,可以看 ElementType这个枚举下面,其实有很多,可以选择
@Target({ElementType.METHOD,ElementType.FIELD})
// SOURCE< CLASS<RUNTIME 这个是作用的范围,其中下面的包含关系,其中范围最大的是RUNTIME,三个地方都会其中,一般自己写的话都会写RUNTIME
@Retention(value=RetentionPolicy.RUNTIME)
@Inherited// 可以被继承
@interface myan{
// 这个不是方法,而是注解的参数。具体写法就是 类型+参数名+()
String name();
String[] interest();
// 如果不写默认值,就需要在使用是时候需要填写值
int age() default 0;
}
@Target({ElementType.METHOD,ElementType.FIELD})
@interface myAn1{
// value 是最神奇的一个参数值,其如果写value 不需要使用 value=value的值
String value();
}
注解,目前可以先知道即可,不过其很多时候用在框架当中,其实后面很多框架都采用了反射+注解的模式。后面如果有涉及再聊。