Annotation是从JDK1.5开始提供为程序元素(包、类、构造器、方法、成员变量、参数、局部变量)设置元数据的一个接口
,这些信息被存储在Annotation的name=value对中
,本篇笔记用于记录什么是Annotation?
、什么是基本Annotation及其作用?
、什么是JDK元Anntation及其作用?
基本的Annotation是由JDK的java.lang
所提供
注解 | 释义 | 特别说明 |
---|---|---|
@Override | 重写 | @Override只能修饰方法 ,不能修饰其他程序元素 |
@Deprecated | 已过时 | 可以修饰类、方法等 |
@SuppressWarnings(value = “unchecked”) | 抑制编译器警告 | 一定要写unchecked为该注释成员变量设置值 |
@SafeVarags | 修饰”堆污染”警告 | Java7专门抑制”堆污染”警告提供的 |
@FunctionalInterface | Java8的函数式接口 | Java8专门提供,只能修饰接口 ,不能修饰其他元素 |
- 编程中尽量多使用
@Override
注释,这样可以在编译的时候编译器就检查出问题
public class Person {
public void name(){
System.out.println("I am oliver");
}
}
class Me extends Person{
@Override
public void name(){
System.out.println("I am AverageJoeWang");
}
}
知识兔二、JDK元Annotation
元Annotation用于修饰其他的Annotation定义
注解 | 释义 |
---|---|
@Retention | 注解保留策略 |
@Target | 指定Annotation可以放置的位置(被修饰的目标) |
@Documented | 指定被修饰的该Annotation可以被javadoc工具提取成文档 |
@Inherited | 指定被它修饰的Annotation 将具有继承性 |
@Repeatable | Java8新加特性 ,可重复的注解 |
@Retention注解
@Retention(RetentionPolicy.RUNTIME)
public @interface anno {}
知识兔- RetentionPolicy的value值只有三个,分别是
SOURCE
,CLASS
,RUNTIME
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
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
}
知识兔@Target
@Target指定Annotation可以放置的位置(被修饰的目标)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
知识兔public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ 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}
@Documented
@Documented指定被修饰的该Annotation可以被javadoc工具提取成文档.
@Inherited
@Inherited
指定被它修饰的Annotation
将具有继承性,如果某个类使用了如果某个类使用@Xxx
注解(该Annotation
使用了@Inherited
修饰)修饰, 则其子类自动被@Xxx
注解修饰.
@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Inherited {}
三、自定义注解
- 使用
@interface
自定义注解时,自动继承了java.lang.annotation.Annotation
接口
public interface Annotation { /** * Returns true if the specified object represents an annotation * that is logically equivalent to this one. In other words, * returns true if the specified object is an instance of the same * annotation type as this instance, all of whose members are equal * to the corresponding member of this annotation, as defined below: * <ul> * <li>Two corresponding primitive typed members whose values are * <tt>x</tt> and <tt>y</tt> are considered equal if <tt>x == y</tt>, * unless their type is <tt>float</tt> or <tt>double</tt>. * * <li>Two corresponding <tt>float</tt> members whose values * are <tt>x</tt> and <tt>y</tt> are considered equal if * <tt>Float.valueOf(x).equals(Float.valueOf(y))</tt>. * (Unlike the <tt>==</tt> operator, NaN is considered equal * to itself, and <tt>0.0f</tt> unequal to <tt>-0.0f</tt>.) * * <li>Two corresponding <tt>double</tt> members whose values * are <tt>x</tt> and <tt>y</tt> are considered equal if * <tt>Double.valueOf(x).equals(Double.valueOf(y))</tt>. * (Unlike the <tt>==</tt> operator, NaN is considered equal * to itself, and <tt>0.0</tt> unequal to <tt>-0.0</tt>.) * * <li>Two corresponding <tt>String</tt>, <tt>Class</tt>, enum, or * annotation typed members whose values are <tt>x</tt> and <tt>y</tt> * are considered equal if <tt>x.equals(y)</tt>. (Note that this * definition is recursive for annotation typed members.) * * <li>Two corresponding array typed members <tt>x</tt> and <tt>y</tt> * are considered equal if <tt>Arrays.equals(x, y)</tt>, for the * appropriate overloading of {@link java.util.Arrays#equals}. * </ul> * * @return true if the specified object represents an annotation * that is logically equivalent to this one, otherwise false */ boolean equals(Object obj); /** * Returns the hash code of this annotation, as defined below: * * <p>The hash code of an annotation is the sum of the hash codes * of its members (including those with default values), as defined * below: * * The hash code of an annotation member is (127 times the hash code * of the member-name as computed by {@link String#hashCode()}) XOR * the hash code of the member-value, as defined below: * * <p>The hash code of a member-value depends on its type: * <ul> * <li>The hash code of a primitive value <tt><i>v</i></tt> is equal to * <tt><i>WrapperType</i>.valueOf(<i>v</i>).hashCode()</tt>, where * <tt><i>WrapperType</i></tt> is the wrapper type corresponding * to the primitive type of <tt><i>v</i></tt> ({@link Byte}, * {@link Character}, {@link Double}, {@link Float}, {@link Integer}, * {@link Long}, {@link Short}, or {@link Boolean}). * * <li>The hash code of a string, enum, class, or annotation member-value I <tt><i>v</i></tt> is computed as by calling * <tt><i>v</i>.hashCode()</tt>. (In the case of annotation * member values, this is a recursive definition.) * * <li>The hash code of an array member-value is computed by calling * the appropriate overloading of * {@link java.util.Arrays#hashCode(long[]) Arrays.hashCode} * on the value. (There is one overloading for each primitive * type, and one for object reference types.) * </ul> * * @return the hash code of this annotation */ int hashCode(); /** * Returns a string representation of this annotation. The details * of the representation are implementation-dependent, but the following * may be regarded as typical: * <pre> * @com.acme.util.Name(first=Alfred, middle=E., last=Neuman) * </pre> * * @return a string representation of this annotation */ String toString(); /** * Returns the annotation type of this annotation. * @return the annotation type of this annotation */ Class<? extends Annotation> annotationType();}
- 根据
Annotation
是否包含成员变量,可以把Annotation
分为两类:- 标记
Annotation
: 没有成员变量的Annotation
; 这种Annotation
仅利用自身的存在与否来提供信息; - 元数据
Annotation
: 包含成员变量的Annotation
; 它们可以接受(和提供)更多的元数据;
- 标记
- 定义新注解使用
@interface
关键字, 其定义过程与定义接口非常类似(见上面的@Testable), 需要注意的是:Annotation的成员变量在Annotation定义中是以无参的方法形式来声明的, 其方法名
和返回值类型
定义了该成员变量的名字
和类型
, 而且我们还可以使用default
关键字为这个成员变量设定默认值.
@Inherited@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.TYPE})public @interface MyAnnotation { String name(); int age() default 18;}
public class TestAnnotation { @MyAnnotation(name = "abc") public void execute(){ System.out.println("method"); }}
四、提取Annotation信息
- 使用
注解
修饰了类/方法/成员变量等之后,这些注解不会自己生效
,必须由这些注解的开发者提供相应的工具
来提取并处理注解信息(当然,只有当定义注解时使用了@Retention(RetentionPolicy.RUNTIME)
修饰,JVM才会在装载class文件时提取保存在class文件中的注解,该注解才会在运行时可见,这样我们才能够解析). Java使用Annotation接口
来代表程序元素前面的注解
,该接口是所有注解的父接口。
获取Class的实例三种方法
- 利用对象调用getClass()方法获得Class实例
- 利用Class类的静态的forName()方法,使用类名获得Class实例
- 运用.class的方式获得Class实例,如:类名.class
实例
- interface MyAnnotation
import java.lang.annotation.ElementType;import java.lang.annotation.Inherited;import java.lang.annotation.Retention;import java.lang.annotation.RetentionPolicy;/** * Created by oliverwang on 2018/2/27. */@Inherited@Retention(RetentionPolicy.RUNTIME)@Target({ElementType.METHOD, ElementType.TYPE})public @interface MyAnnotation { String name(); int age() default 18;}
- TestAnnotation
import java.lang.annotation.Annotation;/** * Created by oliverwang on 2018/2/27. */public class TestAnnotation { @MyAnnotation(name = "abc") public void execute(){ System.out.println("method"); } @MyAnnotation(name = "oliver") public void info(){ try { Annotation [] annotation = Class.forName("TestAnnotation").getMethod("info").getAnnotations(); for (Annotation annotation1 : annotation){ System.out.println(annotation1); } }catch (Exception e){ e.printStackTrace(); } } public static void main(String[] args){ TestAnnotation testAnnotation = new TestAnnotation(); testAnnotation.info(); }}
- 输出结果:
@MyAnnotation(age=18, name=oliver)
五、模拟JUnit
- 注解Testable接口
/** * Created by oliverwang on 2018/2/27. */@Inherited@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)public @interface Testable {}
- TestCase
/** * Created by oliverwang on 2018/2/27. */public class TestCase { @Testable public void test1(){ System.out.println("test1"); } public void test2(){ System.out.println("test2"); } @Testable public void test3(){ System.out.println("test3"); } public void test4(){ System.out.println("test4"); } @Testable public void test5(){ System.out.println("test5"); }}
- TestableProcessor
/** * Created by oliverwang on 2018/2/27. */public class TestableProcessor { public static void process(String className) throws ClassNotFoundException, IllegalAccessException, InstantiationException { int passed = 0; int failed = 0; Object obj = Class.forName(className).newInstance(); for (Method method : Class.forName(className).getMethods()) { if (method.isAnnotationPresent(Testable.class)) { try { method.invoke(obj); ++passed; } catch (IllegalAccessException | InvocationTargetException e) { System.out.println("method " + method.getName() + " execute error: < " + e.getCause() + " >"); e.printStackTrace(System.out); ++failed; } } } System.out.println("共运行" + (failed + passed) + "个方法, 成功" + passed + "个, 失败" + failed + "个"); } public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException { TestableProcessor.process("TestCase"); }}
- 结果
test1test3test5共运行3个方法, 成功3个, 失败0个