注解和反射
反射
反射允许对成员变量,成员方法和构造方法的信息进行编程访问.
反射可以把类的成员变量, 构造方法, 成员方法的所有信息都获取出来(修饰符, 类型, 需要的数据等等)如java里通过创建对象调用类的方法所给的提示就用到了反射, 提示里面的方法名, 需要的参数, 返回的类型等都通过反射获取.
反射先获取类的class对象,再从class对象中获取字段, 构造方法, 成员方法, 然后再解剖出它们的具体的一些属性
获取class对象的三种方式
- Class.forName("全类名");
- 类名.class
- 对象.getClass();
利用反射获取构造方法, 成员变量, 成员方法
package cn.itcast.a01;import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Parameter;public class MyReflectDemo2 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {/** Class类中用于获取构造方法的方法* Constructor<?>[] getConstructors()* Constructor<?>[] getDeclaredConstructors()* Constructor<?> getConstructor(Class<?>...parameterTypes)* Constructor<?> getDeclaredConstructor(Class<?>...parameterTypes)** Constructor类中用于创建对象的方法* T newInstance(Object...initargs)* setAccessible(Boolean flag)* *///1.获取Class对象Class clazz = Class.forName("cn.itcast.a01.Student");//2.获取构造方法Constructor[] con1 = clazz.getConstructors();for (Constructor c : con1) {System.out.println(c);}Constructor[] con2 = clazz.getDeclaredConstructors();for (Constructor c : con2) {System.out.println(c);}Constructor con3 = clazz.getConstructor();System.out.println(con3);Constructor con4 = clazz.getConstructor(String.class);System.out.println(con4);Constructor con5 = clazz.getDeclaredConstructor(int.class);System.out.println(con5);Constructor con6 = clazz.getDeclaredConstructor(String.class,int.class);System.out.println(con6);//获取构造方法的权限修饰符,获取的修饰符是一个int类型的值int modifiers = con6.getModifiers();System.out.println(modifiers);//获取构造方法的参数列表Parameter[] parameters = con6.getParameters();for (Parameter p : parameters) {System.out.println(p);}//通过获取到的构造方法创建对象(参数必须一致)//暴力反射:临时取消权限校验con6.setAccessible(true);Student stu = (Student) con6.newInstance("张三", 18);System.out.println(stu);}
}
小结:
- 构造方法-->Constructor 成员变量-->Field 成员方法-->Method
- 获得公共元素get...s()
- 获得全部元素getDeclared...s()
- 获取一个公共元素get...(元素的关键信息如需要的参数, 名字等)
- 获取一个元素getDeclared...(元素的关键信息如需要的参数, 名字等)
注解(Annotation)
- 就是java代码里的特殊标记, 比如: @Override, @Test等, 作用是: 让其他程序根据注解信息来决定怎么执行该程序.
- 注意: 注解可以用在类上, 构造器上, 成员变量上, 参数上, 等位置处.
自定义注解
自定义注解: 自己定义的注解.
public @interface 注解名称 {
public 属性类型 属性名() default 默认值;
}
特殊属性名: value
如果注解中只有一个value属性, 使用注解时, value名称可以不写!!
注解的原理
- 注解本质是一个接口, java中所有注解都是继承了Annotation接口的.
- @注解(...): 其实就是一个实现类对象, 实现了该注解以及Annotation接口.
元注解
- 指的是: 修饰注解的注解
常用的两个注解@Target和@Retention
@Target
作用: 声明被修饰的注解只能在哪些位置使用
声明的时候可以声明多个, 如@Target(ElementType.TYPE, ElementType.Method)
@Target(ElementType.TYPE)
- TYPE 类,接口
- FIELD 成员变量
- METHOD 成员方法
- PARAMETER 方法参数
- CONSTRUCTOR 构造器
- LOCAL_VARIABLE 局部变量
@Retention
作用: 声明注解的保留周期
@Retention(RetentionPolicy.RUNTIME)
- SOURCE 只作用在源码阶段, 字节码文件中不存在
- CLASS(默认值) 保留到字节码文件阶段, 运行阶段不存在
- RUNTIME(开发常用) 一直保留到运行阶段
注解的解析
什么是注解的解析?
- 注解的解析就是判断类上, 方法上, 成员变量上是否存在著姐, 并把注解里的内容给解析出来.
如何解析注解?
- 指导思想: 要解析谁上面的注解,就应该先拿到谁.
- 比如要解析类上的注解,则应该先获取该类的Class对象, 在通过Class对象解析其上面的注解
- 比如要解析成员方法上的注解, 则应该先拿到该成员变量的Method对象, 再通过Method对象解析其上面的注解
- Class, Method, Field, Constructor都实现了AnnotatedElement接口, 它们都拥有解析注解的能力.
import org.junit.Test;import java.util.Arrays;public class Annotation3 {@Testpublic void parseClass(){//1.获取Class对象Class c = Demo.class;//2.解析类上的注解//判断类上是否有MyTest4注解if(c.isAnnotationPresent(MyTest4.class)){MyTest4 myTest4 = (MyTest4)c.getDeclaredAnnotation(MyTest4.class);System.out.println(myTest4.value());System.out.println(myTest4.aaa());System.out.println(Arrays.toString(myTest4.bbb()));}}
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
import java.lang.reflect.Method;public class Anntation4 {@MyTestpublic void test1(){System.out.println("===test1===");}
// @MyTestpublic void test2(){System.out.println("===test2===");}@MyTestpublic void test3(){System.out.println("===test3===");}
// @MyTestpublic void test4(){System.out.println("===test4===");}public static void main(String[] args) throws Exception {Anntation4 a = new Anntation4();//启动程序//1.获取Class对象Class clazz = Anntation4.class;//2.获取所有方法Method[] methods = clazz.getDeclaredMethods();for (Method method : methods) {//3.判断方法上是否有@MyTest注解if (method.isAnnotationPresent(MyTest.class)){//4.如果有,调用方法method.invoke(a);}}}
}