常常在代码中看到注解,经常使用的有@Override、@Deprecated、Spring注解。html
@Override代码以下:java
package java.lang; import java.lang.annotation.*; @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
Override里面很干净,什么都没有,可是外面有。编程
涉及到了两个元注解:api
@Target :顾名思义,说明@Override能够用来注解方法。oracle
@Retention:定义该注解的生命周期,默认为RetentionPolicy.CLASS。jvm
类型 | 使用场景 | 常见例子 |
RetentionPolicy.SOURCE | 在编译阶段丢弃。这些注解在编译结束以后就再也不有任何意义,因此它们不会写入字节码。 | @Override, @SuppressWarnings都属于这类注解。 |
RetentionPolicy.CLASS | 在类加载的时候丢弃。在字节码文件的处理中有用。注解默认使用这种方式。 | |
RetentionPolicy.RUNTIME | 始终不会丢弃,运行期也保留该注解,所以可使用反射机制读取该注解的信息。 | 咱们自定义的注解一般使用这种方式。 |
查api doc,看到还有另外两种元注解:ide
@Documented:注解是否将包含在JavaDoc中函数
@Inherited:是否容许子类继承该注解spa
另外,还发现了一个Annotation接口:.net
package java.lang.annotation; public interface Annotation { boolean equals(Object obj); int hashCode(); Class<? extends Annotation> annotationType(); }
此接口功能以下(虽然有点绕,可是说的仍是挺清楚地):
一、任何注解都继承了此接口;
二、经过 xxInterface extends Annotation方式继承的不声明注解;
三、此接口本身没有声明注解。
从这个知乎问题知道,注解反编译以后实际上继承了Annotation。
言归正传,看过了@Override的代码,会产生2个疑问:
一、@Override的功能(检查在父类中有一个相同签名的函数)是谁来完成的?
二、如何自定义一个注解?
咱们先说第二个问题~
1、如何自定义一个Annotation?
简单如@Retention,发现Retention能够本身注解本身,这不算犯规。
package java.lang.annotation; @Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }
自定义代码(引自refer2连接):
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { int count() default 1; // 默认是public,default不是必须的,方法必须有返回值; } @TestAnnotation(count = 0x7fffffff) public class TestMain { public static void main(String[] args) throws InterruptedException, NoSuchFieldException, IllegalAccessException, IOException { TestAnnotation annotation = TestMain.class.getAnnotation(TestAnnotation.class); System.out.println(annotation.count()); System.in.read(); } }
refer3里有个Filed的例子,这个博客被转的还蛮多的。
2、@Override的功能是谁来完成的?
如今的java IDE都是自动编译的,编译的时候就能够检查是否正确的Override了父类的方法了~
PS: JVM是如何选择@Override的方法的?
看了一些博客以后,大概明白了。因为继承的存在,变量具备“静态类型”和“实际类型”,静态类型在编译器肯定,实际类型在运行期肯定,执行的时候调用实际类型的Override的方法便可。
Override和Overload的底层实现叫作“分派”(原谅本身第一次见到这个词)。发现Override是jvm的一个叫“动态分派”的过程完成的,与之相对的静态分派是重载(Overload)。除此以外还有多分派、单分派这对术语。
3、相关问题
一、Spring中使用注解注册Bean;
refer: