目录
反射:框架设计的灵魂
1、类的三种获取方式
(1)、Class.forName("全类名")
(2)、类名.class
(3)、对象.getClass()
1.1、三种类获取方法的相同之处
Field成员变量的获取
Constructor构造方法的获取
Merhod类里面方法的获取
最后来个案例融会贯通一下吧
反射:框架设计的灵魂
反射机制:将类(Class
功能:
在运行时分析类的能力;在运行时查看对象;实现通用的数组操作代码;可以解耦;
为了方便理解,我们先看一下Java程序运行的三个阶段:
第一个阶段:源码阶段,源码通常保存在硬盘上,所以第一阶段就是从硬盘上读取字节码。
第二个阶段:内存阶段,要知道一个程序运行,并非是直接在硬盘上运行的(否则要内存条何用),而是在内存里运行的。所以第二个阶段就是通过类加载器从硬盘上把类加载到内存里。
第三个阶段:运行阶段,这个阶段才是我们所熟悉的运行阶段。对象的创建以及方法的执行就是在这个阶段(如何运行的就要去看计算机的操作系统原理了)
而类的三种获取方法也对应这三个不同的阶段。
1、类的三种获取方式
(1)、Class.forName("全类名")
(2)、类名.class
(3)、对象.getClass()
| 方式 | 阶段 | 异同 |
|---|---|---|
| Class.forName("全类名") | 源码阶段 | 将字节码文件加载进内存(源码阶段),返回Class对象,全类名通常定义在配置文件中,便于利反射机制生成类对象,加载类。 这个方法只有在forName是类名或者接口名才能使用,否则将抛出一个chekedException。所以无论什么时候,使用forName时都应该提供一个异常处理器 |
| 类名.class | 内存阶段 | 类加载进内存后从类名获取(内存阶段) 想想为什么是.class而不是.class()? 通常 类名.属性 代表什么?类的静态属性,直接通过类名调用 |
| 对象.getClass() | 运行阶段 | 这个就比较容易理解,通过对象获取该对象的类。而对象是在(运行阶段)创建的。 |
(1)、Class.forName("全类名")
将字节码文件加载进内存(源码阶段),返回Class对象,全类名通常定义在配置文件中,便于利反射机制生成类对象,加载类。
这个方法只有在forName是类名或者接口名才能使用,否则将抛出一个chekedException。所以无论什么时候,使用forName时都应该提供一个异常处理器
(2)、类名.class
类加载进内存后从类名获取(内存阶段)
想想为什么是.class而不是.class()?
通常 类名.属性 代表什么?类的静态属性,直接通过类名调用
(3)、对象.getClass()
这个就比较容易理解,通过对象获取该对象的类。而对象是在(运行阶段)创建的。
1.1、三种类获取方法的相同之处
public class test {
public static void main(String[] args) throws Exception {
Person person = new Person();
Class aClass = Class.forName("reflective.Person");
Class personClass = Person.class;
Class aClass1 = person.getClass();
if (aClass == personClass && personClass == aClass1) {
System.out.println("三个方法获取的是同一个地址");
}
}
}
输出结果:
三个方法获取的是同一个地址
由此可见,三种方法应用的都是同一个地址。
Field成员变量的获取
获取到类之后的第二步就是获取成员属性
| Filed[] getFileds() | 返回所有public修饰的成员变量(只能用于public关键字) |
| Filed[] getFiled(String filedName) | 返回特定public修饰的成员变量(只能用于public关键字) |
| Filed[] getDeclaredFields() | 返回所有变量,不考虑修饰符 |
| Filed[] getDeclaredField(String filedName) | 返回特定的成员变量,获取私有属性时关键字安全检查机制可能会报异常,这时候就要用到setAccessible(true);来忽略安全检查了,这步骤也叫暴力反射 |
import java.lang.reflect.Field;
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
//获取person的class对象
Class personClass = Person.class;
//Filed[] getFileds()是用来返回所有public修饰的成员变量
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("---------------");
Field a = personClass.getField("a");
Person person = new Person();
System.out.println(a.get(person));
//设置a的值
a.set(person,"张三");
System.out.println(person);
System.out.println("=============");
//Filed[] getDeclaredFields() 获取所有变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
//Filed
Field declaredField = personClass.getDeclaredField("d");
//忽略访问修饰符的安全检查
declaredField.setAccessible(true); //暴力反射
Object value = declaredField.get(person);
System.out.println(value);
}
}
Constructor构造方法的获取
获取了成员属性后就是获取类的构造方法了
使用 Constructor getConstructor(Class>...) 获取构造方法
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectGetConstructor {
public static void main(String[] args) throws Exception {
//获取person的class对象
Class personClass = Person.class;
//Constructor getConstructor(Class>...)
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//使用获取到的构造方法创建对象
Object person1 = constructor.newInstance("Sun", 23);
System.out.println(person1);
}
}
Merhod类里面方法的获取
最后一步就是方法的获取了,取得一个类功能的关键性一步
获取方法:对象.getMethod("类名");
public class ReflectGetMethod {
public static void main(String[] args) throws Exception{
Class personClass = Person.class;
//personClass.getMethod
Method eat_method = personClass.getMethod("eat");
Person person = new Person();
//执行方法
eat_method.invoke(person);
Method eat_method2 = personClass.getMethod("eat", String.class);
eat_method2.invoke(person,"饭");
System.out.println(eat_method2.invoke(person,"粥"));
//获取所有的public方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
//获取方法名
String name = method.getName();
System.out.println(name);
//method.setAccessible(ture)
}
//获取类名
String className = personClass.getName();
System.out.println(className);
}
}
最后来个案例融会贯通一下吧
测试类:
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectTest {
public static void main(String[] args) throws Exception {
//可以创建任意的对象,可以创建按任意的方法
//1.加载配置文件
//1.1创建properties对象
Properties properties = new Properties();
//1.2加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
properties.load(resourceAsStream);
//2.获取配置文件中定义的数据
String clessName = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
//3.使用加载技术来加载类文件进内存
Class> aClass = Class.forName(clessName);
//4.创建对象
Object o = aClass.newInstance();
//5.获取方法对象
Method method = aClass.getMethod(methodName);
//6.执行方法
method.invoke(o);
}
}
新建个Student类,类里面有一个sleep方法
新建一个配置文件 pro.roperties
以后创建的对象以及调用的方法就直接在配置文件里操作就可以啦!
className = reflective.student.Student
methodName = sleep
来一个运行结果来奖励一下自己
获取了成员属性后就是获取类的构造方法了
使用 Constructor
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectGetConstructor {
public static void main(String[] args) throws Exception {
//获取person的class对象
Class personClass = Person.class;
//Constructor getConstructor(Class>...)
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//使用获取到的构造方法创建对象
Object person1 = constructor.newInstance("Sun", 23);
System.out.println(person1);
}
}
Merhod类里面方法的获取
最后一步就是方法的获取了,取得一个类功能的关键性一步
获取方法:对象.getMethod("类名");
public class ReflectGetMethod {
public static void main(String[] args) throws Exception{
Class personClass = Person.class;
//personClass.getMethod
Method eat_method = personClass.getMethod("eat");
Person person = new Person();
//执行方法
eat_method.invoke(person);
Method eat_method2 = personClass.getMethod("eat", String.class);
eat_method2.invoke(person,"饭");
System.out.println(eat_method2.invoke(person,"粥"));
//获取所有的public方法
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
//获取方法名
String name = method.getName();
System.out.println(name);
//method.setAccessible(ture)
}
//获取类名
String className = personClass.getName();
System.out.println(className);
}
}
最后来个案例融会贯通一下吧
测试类:
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReflectTest {
public static void main(String[] args) throws Exception {
//可以创建任意的对象,可以创建按任意的方法
//1.加载配置文件
//1.1创建properties对象
Properties properties = new Properties();
//1.2加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectTest.class.getClassLoader();
InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
properties.load(resourceAsStream);
//2.获取配置文件中定义的数据
String clessName = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
//3.使用加载技术来加载类文件进内存
Class> aClass = Class.forName(clessName);
//4.创建对象
Object o = aClass.newInstance();
//5.获取方法对象
Method method = aClass.getMethod(methodName);
//6.执行方法
method.invoke(o);
}
}
新建个Student类,类里面有一个sleep方法
新建一个配置文件 pro.roperties
以后创建的对象以及调用的方法就直接在配置文件里操作就可以啦!
className = reflective.student.Student methodName = sleep
来一个运行结果来奖励一下自己



