1. 什么是反射
反射是框架设计的灵魂
反射:在类运行期间,借助Reflection API 把类中成员抽取为其他类,取得任何类的内部信息,并能直接操作任意对象的属性和方法。
把类中成员抽取为其他类:把java类中的各种成分映射成一个个的Java对象,例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
源文件:.java文件,存放在磁盘中
字节码文件:.class文件,同样存放在磁盘中
Java程序的执行包含两个阶段:编译阶段、运行阶段
编译阶段:
.java(源码)——》使用JDK当中自带的**javac**.exe命令进行java程序的编译——》得到.class字节码文件【最终要执行的文件】
以上源文件和字节码文件均存放在磁盘中
运行阶段:
JDK中的java.exe主要负责运行阶段
- java.exe命令会启动Java虚拟机(JVM)
- JVM会启动**类加载器(ClassLoader)**
- 类加载器会去硬盘上搜索类名.class文件,找到该文件
- 将该字节码文件装载到JVM中,以Class的形式存在
- JVM将该字节码文件解释成二进制数据
- 操作系统执行二进制和底层硬件平台进行交互
上述文件存放在内存中
2. 为什么使用反射
反射是为了解决在运行期间,对某个实例一无所知的情况下,如何调用其他方法或属性
反射使用的前提条件:必须先得到代表的字节码的Class
Idea通过反射获取类中所有的method方法对象,以提示框的形式列出
3. 获取Class反射类的方式
提供了三种获取Class反射类的方法
- 第一种:通过类名.class属性
//1. 通过类名.class获取
Class studentClass = Student.class;
- 第二种:通过类路径获取【加载驱动时用过】
//2. 通过路径获取
Class aClass = Class.forName("com.zmq.entity.Student");
- 第三种:通过对象名获取反射类型
//3.通过对象获取
//创建一个类对象
Student student=new Student();
//通过getClass方法获得Class反射类
Class aClass1 = student.getClass();
4. Class类中常用的方法
- newInstance:通过反射类创建类对象
//获取到反射类
Class<Student> studentClass = Student.class;
//通过反射类创建对象
Student student = studentClass.newInstance();
System.out.println(student);
- getAnnotation:获取反射类上的注解对象
//获取反射类上面的所有注解
MyAnnotation annotation = studentClass.getAnnotation(MyAnnotation.class);
System.out.println(annotation.value());
getAnnotation()是Java中反射API中的一个方法,用于获取某个类、方法或字段的注解信息。可以通过该方法获取指定注解类型的注解实例。在使用该方法时,需要提供注解的Class对象作为参数,如果要获取某个方法或字段上的注解,则需要先获取该方法或字段的对象,再调用 getAnnotation()方法获取注解实例。
5. Method类对象中常用的方法
- getDeclaredMethods():获取本类中定义的所有Methods类对象
//获取反射类
Class<Student> studentClass = Student.class;
//获取本类中的所有Method对象
Method[] declaredMethods = studentClass.getDeclaredMethods();
for (Method m: declaredMethods) {
System.out.println(m);
}
System.out.println("+++++++++++++++++++++++++");
- getDeclaredMethod(“方法名”,参数类型):获取本类中指定的方法对象
//获取本类中指定的Method对象
Method fun = studentClass.getDeclaredMethod("fun");
System.out.println(fun);
System.out.println("**********************");
- getMethods():获取本类和父类中所有的public方法对象
//获取本类和父类中的所有public方法
Method[] methods = studentClass.getMethods();
for (Method m:methods) {
System.out.println(m);
}
System.out.println("");
- getMethod(“方法名”,参数类型):获取本类和父类中指定的public方法对象
//获取本类和父类中指定的public方法
Method show = studentClass.getMethod("show");
System.out.println(show);
System.out.println("--------------------");
Method fun1 = studentClass.getMethod("fun");
System.out.println(fun1);
6. Method类对象中常用的方法
Class<?>:?表示泛型通配符
- invoke( Object obj, Object… args):调用类中的方法,返回该方法执行的结果。第一个参数表示执行方法的对象,第二个参数表示执行方法的方法参数
//获取反射类
Class<Student> studentClass = Student.class;
//通过反射类创建对象
Object o = studentClass.newInstance();
//获取本类和父类中指定的public方法
Method age = studentClass.getMethod("ages",Integer.class);
//通过invoke方法,执行该方法,返回该方法执行的结果
//第一个参数表示执行方法的对象
Object invoke = age.invoke(o, 25);
System.out.println(invoke);
若在实体类方法中没有返回值,为void,打印输出上述invoke为null。若在上述基础上,方法提内有打印输出语句,则该语句会作为返回结果输出,打印输出invoke为null。
若有返回值,如String,打印输出对应结果
- 暴力访问私有方法——通过getDeclaredMethod()获取指定的私有方法
- setAccessible():暴力访问
//暴力访问private方法
//获取指定的方法,私有的
Method age1 = studentClass.getDeclaredMethod("age", int.class);
//暴力访问
age1.setAccessible(true);
Object invoke1 = age1.invoke(o, 30);
System.out.println(invoke1);
7. 获取Filed属性对象的方式
同获取Method方法类对象相似,也提供四种方法
- getDeclaredFields():获取本类中的所有属性
//获取反射类
Class<Student> studentClass = Student.class;
//通过反射类创建对象
Student student = studentClass.newInstance();
//获取本类中的所有属性
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field f:declaredFields) {
System.out.println(f.getName());
}
System.out.println("---------");
- getDeclaredField(“属性名”):获取指定的属性
//获取指定的属性
Field names = studentClass.getDeclaredField("names");
- getFields():获取本类和父类的所有public属性
//获取本类和父类中的所有public属性
Field[] fields = studentClass.getFields();
for (Field f:fields) {
System.out.println(f.getName());
}
System.out.println("+++++++++++++");
- getField(“属性名”):获取本类和父类中指定的public属性
//获取本类和父类中指定的public属性
Field names1 = studentClass.getField("names");
System.out.println(names1);
8. Filed类中常用的方法
- set(Object对象,值):为属性赋值
//获取反射类
Class<Student> studentClass = Student.class;
//通过反射类创建对象
Student student = studentClass.newInstance();
//获取指定的属性
Field names = studentClass.getDeclaredField("names");
//为属性赋值
names.set(student,"lay");
//获取私有属性
Field sex = studentClass.getDeclaredField("sex");
//暴力访问
sex.setAccessible(true);
//为属性赋值
sex.set(student,"男");
System.out.println(student);
System.out.println("=================");
- getName():获取属性名
//获取本类中的所有属性
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field f:declaredFields) {
//获取属性名
System.out.println(f.getName());
}
System.out.println("---------");
- getAnnotation():获取属性上的注解对象
//获取本类中的所有属性
Field[] declaredFields = studentClass.getDeclaredFields();
for (Field f:declaredFields) {
//获取属性名
System.out.println(f.getName());
//获取属性上的注解
MyAnnotation annotation = f.getAnnotation(MyAnnotation.class);
String value = annotation.value();
System.out.println(value);
}
System.out.println("---------");
获取的注解若返回类型为Annotation,则获取value值时需要强转为MyAnnotation
9. 案例
在properties属性文件中指定类的路径,通过反射完成类对象的创建以及类中属性的赋值
public class Test06 {
public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
//1. 创建属性文件对象
Properties properties=new Properties();
//2. 读取属性文件
//2.1 输入
InputStream resourceAsStream = Test06.class.getClassLoader().getResourceAsStream("zmq.properties");
//2.2 读取
properties.load(resourceAsStream);
//3. 属性类读取属性文件中指定的key的值
String className = properties.getProperty("className");
//4. 根据类路径得到反射对象
Class<?> aClass = Class.forName(className);
//5. 根据反射类创建对象
Object o = aClass.newInstance();
System.out.println(o);
//6. 为属性赋值
Field[] declaredFields = aClass.getDeclaredFields();
for (Field f:declaredFields) {
//暴力访问
f.setAccessible(true);
//为属性赋值
f.set(o,new Random().nextInt(100)+"");
}
System.out.println(o);
}
}
通过案例可以得知,反射是在运行时,对原来类一无所知的情况下执行