注解分为内置注解和元注解以及自定义注解,内置注解就是平常经常使用的,比如@Override、@SpringBootApplication等等,当java程序运行的时候,可以通过反射获取注解信息,从而针对被注解的方法或者类进行相应的处理。元注解就是定义注解的注解,用来声明注解的使用范围,时间等等。
元注解一共有六个。第一个@Documented:被@Documented修饰的注解会被JavaDoc提取成文档,一般不会用了解即可。第二个注解@Native:被@Native注解修饰的注解可以用于修饰成员变量,该成员变量可以被本地代码引用,一般不会用了解即可。 第三个注解@Repeatable:被@Repeatable注解修饰的注解可以重复使用,一般也不会用。 第四个注解@Target注解:@Target注解可以指定修饰的注解的使用地方。通过ElementType枚举类中的元素来指定,比如@Target({ElementType.ANNOTATION_TYPE,ElementType.FIELD})。ElementType中有以下几个元素CONSTRUCTOR(构造方法),FIELD(成员变量),LOCAL_VARIABLE(局部变量),METHOD(方法),PACKAGE(包),PARAMETER(参数),TYPE(类或者接口)。第五个注解@Retention:被@Retention修饰的注解可以指定修饰的注解的作用时间,通过RetentionPolicy中的元素来指定,比如@Retention(RetentionPolicy.CLASS)。RetentionPolicy枚举类中有以下几个元素SOURCE(源文件),CLASS(class文件中),RUNTIME(运行时)。第六个注解@Inherited:被@Inherited注解修饰的注解可以被子类自动继承。
@Annotation.MyAnnotation(name = "SuperQin") public class Annotation { @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation { //注解元素:类型+名称(); String name() ; //default 注解元素默认值 int age() default 0; } }
反射Reflection是框架设计的灵魂,所谓的反射简而言之就是在代码运行的时候可以获取运行时的类的结构,从而可以根据结构做出不同的反应,比如上面讲到的注解。但是请注意反射需要慎用,因为反射的速度会远远低于正常程序的运行速度。在JVM中每个类有且仅有一个对象,平时NEW出来的实例化对象都会指向这个唯一的对象。
static class MyReflection1{ public MyReflection1(){ System.out.println("反射1"); } } static class MyReflection2 extends MyReflection1{ public MyReflection2(){ System.out.println("反射2"); } } public static void main(String[] args) throws ClassNotFoundException { MyReflection1 myReflection1 = new MyReflection1(); Class cl1 = myReflection1.getClass(); Class cl2 = MyReflection1.class; Class cl3 = Class.forName("zgq.reflectionandannotation.Reflection.MyReflection1"); Class cl4 = Integer.TYPE; Class cl5 = cl3.getSuperclass(); }
得到类的唯一对象之后就可以通过该对象获取该类所有的结构。并且进行操作。
//获取类名 cl1.getName(); //获取类中public的属性 cl1.getFields(); //获取类中所有属性 cl1.getDeclaredFields(); //获取本类中所有的方法 cl1.getDeclaredMethods(); //获取类中及父类中public方法 cl1.getMethods(); //获得构造器 cl1.getConstructors(); //通过构造器创建对象 cl1.getConstructor().newInstance(); //通过对象创建对象 cl1.newInstance(); //通过反射调用方法 cl1.getMethod("test1").invoke(cl1.newInstance()); //通过反射调用属性 cl1.getField("a").set(cl1.newInstance(),"设置属性"); //以上操作属性和方法不能操作私有的方法和属性,需要关闭安全检测,也可以加快反射速度 cl1.getField("a").setAccessible(true); cl1.getMethod("test1").setAccessible(true); //获取方法参数泛型 cl1.getMethod("test1").getGenericParameterTypes(); //获取方法返回值泛型 cl1.getMethod("tets1").getGenericReturnType(); //获取方法异常信息泛型 cl1.getMethod("test").getGenericExceptionTypes();
最后还有就是通过反射获取注解。可以获取对应的方法,类,属性上的注解
public static void main(String[] args) throws NoSuchMethodException { Class cl1 = Reflection.class; Method method = cl1.getMethod("annotationTest"); Annotation1 annotation1 = method.getAnnotation(Annotation1.class); System.out.println(annotation1.test()); } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface Annotation1{ String test(); } @Annotation1(test = "反射获取注解测试") public void annotationTest(){ }