文章目录
- 一、Java代码在计算机中经历的三个阶段
- 二、常用API的运用
- (一)获取class对象的三种方式
- (二)获取成员变量
- 1.Field[] getFields()
- 2.Field getField(String name)
- 3.Field[] getDeclaredFields()
- 4.Field getDeclaredField(String name)
- 5.Field:成员变量
- (三)获取构造方法
- 1.Constructor getConstructor(类<?>... parameterTypes)
- 2.Constructor<?>[] getConstructors()
- 3.Constructor getDeclaredConstructor(类<?>... parameterTypes)
- 4.Constructor<?>[] getDeclaredConstructors()
- 5.Constructor:构造函数
- (四)获取成员方法
- 1.Method getMethod(String name, 类<?>... parameterTypes)
- 2.Method[] getMethods()
- 3.Method getDeclaredMethod(String name, 类<?>... parameterTypes)
- 4.Method[] getDeclaredMethods()
- 5.Method:方法对象
- (五)获取类名
- 三、运用案例
反射是框架设计的灵魂
想要通过Java的反射机制获取类的信息,就必须先获取Class对象
一、Java代码在计算机中经历的三个阶段
(一):源代码阶段
创建一个Person类对象。此时,计算机硬盘上会生成一个Person.java文件,再通过javac编译器编译Person.java文件,会生成一个字节码person.class文件。
字节码person.class文件包含了Person.java文件中的所有内容,但不仅仅这些内容。
(二):Class类对象
通过类加载器ClassLoader,将字节码文件person.class,加载到内存中,生成一个Class类对象。
想要使用反射,就必须先得到Class类对象。
(三):运行时阶段
我们创建对象的时候new Person();就是运行时阶段。
综上所述:Java的反射机制,就是将Java类文件>>>>通过javac编译器,生成>>>>字节码文件>>>>通过类加载器ClassLoader,生成>>>>一个Class类对象。Class类对象中包含了Java类文件中所有的内容,通过Class类对象操作类的过程称之为反射。
二、常用API的运用
(一)获取class对象的三种方式
1.Class.forName(String className)
将字节码文件加载至内存,返回class对象;
多用于配置文件,将类名定义在配置文件中,读取文件加载类。
/**
* className:包名+类名
*/
Class<?> cls01 = Class.forName("cn.zj.domain.Person");
System.out.println(cls01);
2.类名.class
通过类名的属性class获取;
多用于参数的传递
Class<Person> cls02 = Person.class;
System.out.println(cls02);
3.对象.getClass()
getClass()在Object中定义,也就是说,所有的类的有这个方法;
多用于有对象的情况下,需要获取该对象的字节码对象。
Person person = new Person();
Class cls03 = person.getClass();
System.out.println(cls03);
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
(二)获取成员变量
1.Field[] getFields()
获取所有public修饰的成员变量
Class<Person> personClass = Person.class;
/**
* 获取所有public修饰的成员变量
*/
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
2.Field getField(String name)
获取指定的public修饰的成员变量
Class<Person> personClass = Person.class;
/**
* 获取指定的public修饰的成员变量
*/
Field a = personClass.getField("a");
3.Field[] getDeclaredFields()
获取所有的成员变量
Class<Person> personClass = Person.class;
/**
* 获取所有成员变量
*/
Field[] declaredFields = personClass.getDeclaredFields();
for (Field field :
declaredFields) {
System.out.println(field);
}
4.Field getDeclaredField(String name)
获取指定的成员变量,不管指定的成员变量的修饰符是什么。
Class<Person> personClass = Person.class;
/**
* 获取指定的成员变量,不管是何总修饰符修饰的
*/
Field d = personClass.getDeclaredField("d");
System.out.println(d);
5.Field:成员变量
5.1.获取值
Object get(Object obj)
获取成员变量的值;
/**
* 获取指定的public修饰的成员变量
*/
Field a = personClass.getField("a");
Person person = new Person();
/**
* 获取成员变量a的值
*/
Object value = a.get(person);
System.out.println(value);
如果访问的成员变量受到访问权限修饰符的限制,比如是private修饰的成员变量,则需要暴力反射;
Class<Person> personClass = Person.class;
/**
* 获取指定的成员变量,不管是何种访问权限修饰符
*/
Field d = personClass.getDeclaredField("d");
System.out.println(d);
Person person = new Person();
//忽略访问全限修饰符的检查,
//访问权限修饰符为private,需要设置为true
d.setAccessible(true);
//获取成员变量的值
Object obj = d.get(person);
System.out.println(obj);
5.2.设置值
void set(Object obj, Object value)
设置指定对象成员变量的值
参数 :
obj的字段应该被修改的对象
value为新值
Field a = personClass.getField("a");
Person person = new Person();
/**
* 设置指定成员变量的值
*/
a.set(person,"张三");
System.out.println(person.toString());
(三)获取构造方法
1.Constructor getConstructor(类<?>… parameterTypes)
获取指定参数的public修饰的构造函数
Class<Person> personClass = Person.class;
/**
* 获取指定参数的public修饰的构造函数
*/
Constructor<Person> constructor = personClass.getConstructor(String.class, Integer.class);
System.out.println(constructor);
2.Constructor<?>[] getConstructors()
获取所有public修饰的构造函数
Class<Person> personClass = Person.class;
/**
* 获取所有public修饰的构造函数
*/
Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor con :
constructors) {
System.out.println(con);
}
3.Constructor getDeclaredConstructor(类<?>… parameterTypes)
获取指定参数的构造函数,不考虑权限修饰符
Class<Person> personClass = Person.class;
/**
* 获取指定参数的构造函数,不考虑权限修饰符
*/
Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(Integer.class);
System.out.println(declaredConstructor);
4.Constructor<?>[] getDeclaredConstructors()
获取所有的构造函数,不考虑权限修饰符
Class<Person> personClass = Person.class;
/**
* 获取所有的构造函数,不考虑权限修饰符
*/
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor con :
declaredConstructors) {
System.out.println(con);
}
5.Constructor:构造函数
5.1.创建对象
T newInstance(Object… initargs)
Class<Person> personClass = Person.class;
/**
* 获取指定参数的构造函数
*/
Constructor<Person> constructor = personClass.getConstructor(String.class, Integer.class);
System.out.println(constructor);
Person person = constructor.newInstance("张三", 12);
System.out.println(person);
如果访问的成员变量受到访问权限修饰符的限制,比如是private修饰的成员变量,则需要暴力反射;
/**
* 获取指定参数的构造函数,不考虑权限修饰符
*/
Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(Integer.class);
System.out.println(declaredConstructor);
//此处的构造函数为protected修饰的,需要暴力反射
declaredConstructor.setAccessible(true);
Person person2 = declaredConstructor.newInstance(20);
System.out.println("==========person2==========="+person2);
如果使用空参数构造函数创建对象,上面的方法可以实现,即不传参数即可,但可以简化操作,
Class对象也有创建对象的方法:T newInstance()
Class<Person> personClass = Person.class;
Person person1 = personClass.newInstance();
System.out.println(person1);
(四)获取成员方法
1.Method getMethod(String name, 类<?>… parameterTypes)
获取指定名称和参数的public修饰的成员方法
参数
name:方法名
parameterTypes:方法参数,有就写,没有就不写
Class<Person> personClass = Person.class;
/**
* 获取指定成员方法名称和参数的public修饰的方法
*/
//无参
Method eat = personClass.getMethod("eat");
System.out.println(eat);
//有参
Method eat1 = personClass.getMethod("eat",String.class);
System.out.println(eat1);
2.Method[] getMethods()
获取所有public修饰的成员方法,包含它的父类Object里的方法
Class<Person> personClass = Person.class;
/**
* 获取所有public修饰的成员方法,包含它的父类Object里的方法
*/
Method[] methods = personClass.getMethods();
for (Method method :
methods) {
System.out.println(method);
}
3.Method getDeclaredMethod(String name, 类<?>… parameterTypes)
获取指定的成员方法,不考虑权限修饰符
Class<Person> personClass = Person.class;
/**
* 获取指定的成员方法,不考虑权限修饰符
*/
Method sing = personClass.getDeclaredMethod("sing", Integer.class);
System.out.println(sing);
4.Method[] getDeclaredMethods()
获取所有成员方法,不考虑权限修饰符。不包含父类Object中的方法
Class<Person> personClass = Person.class;
/**
* 获取所有成员方法,不考虑权限修饰符。不包含父类Object中的方法
*/
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method met :
declaredMethods) {
System.out.println(met);
}
5.Method:方法对象
5.1.执行方法
Object invoke(Object obj, Object… args)
调用底层的方法
参数
obj:指定对象
args:指定成员方法的参数
Class<Person> personClass = Person.class;
/**
* 获取指定成员方法名称和参数的public修饰的方法
*/
//无参
Method eat = personClass.getMethod("eat");
System.out.println(eat);
Person person = new Person();
Object obj = eat.invoke(person);
//有参
Method eat1 = personClass.getMethod("eat",String.class);
System.out.println(eat1);
Person person1 = new Person();
Object obj1 = eat1.invoke(person,"饭");
如果访问的成员方法受到访问权限修饰符的限制,比如是private修饰的成员方法,则需要暴力反射;
Class<Person> personClass = Person.class;
/**
* 获取指定的成员方法,不考虑权限修饰符
*/
Method sing = personClass.getDeclaredMethod("sing", Integer.class);
System.out.println(sing);
sing.setAccessible(true);
Person person = new Person();
sing.invoke(person,100);
5.2.获取方法名称
String getName()
Class<Person> personClass = Person.class;
/**
* 获取所有成员方法,不考虑权限修饰符。不包含父类Object中的方法
*/
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method met :
declaredMethods) {
System.out.println(met);
//获取方法名称
String name = met.getName();
System.out.println(name);
}
(五)获取类名
1.String getName()
获取类名,返回为:包名+类名
Class<Person> personClass = Person.class;
//获取类名
String name1 = personClass.getName();
System.out.println("name1: "+name1);
返回值:包名+类名
三、运用案例
需求描述:写一个”框架“,可以创建任意类的对象,并且执行其对象中的任意的方法。
步骤:1.读取配置文件中的内容;
2.将需要运行的类加载进内存
3.利用反射创建对象
4.利用反射获取方法
5.利用反射执行方法
- 创建pro.properties
- 案例代码
package cn.zj.refelect;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 注释
* 框架类
* @author 49906
* @date 2020/3/21
*/
public class RefelectTest {
public static void main(String[] args) throws Exception {
//1.加载配置文件
//1.1.创建Properties对象
Properties properties =new Properties();
//1.2.加载配置文件,转换为一个集合
//获取class目录下的配置文件
ClassLoader classLoader = RefelectTest.class.getClassLoader();
InputStream in = classLoader.getResourceAsStream("pro.properties");
properties.load(in);
//2.获取配置文件中定义的数据
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
//3.加载该类进内存
Class<?> cls = Class.forName(className);
//4.创建对象
Object obj = cls.newInstance();
//5.获取方法对象
Method method = cls.getMethod(methodName);
//6.执行方法
method.invoke(obj);
}
}