创建一个Person类对象。此时,计算机硬盘上会生成一个Person.java文件,再通过javac编译器编译Person.java文件,会生成一个字节码person.class文件。
字节码person.class文件包含了Person.java文件中的所有内容,但不仅仅这些内容。
通过类加载器ClassLoader,将字节码文件person.class,加载到内存中,生成一个Class类对象。
想要使用反射,就必须先得到Class类对象。
我们创建对象的时候new Person();就是运行时阶段。
综上所述:Java的反射机制,就是将Java类文件>>>>通过javac编译器,生成>>>>字节码文件>>>>通过类加载器ClassLoader,生成>>>>一个Class类对象。Class类对象中包含了Java类文件中所有的内容,通过Class类对象操作类的过程称之为反射。
将字节码文件加载至内存,返回class对象;
多用于配置文件,将类名定义在配置文件中,读取文件加载类。
/**
* className:包名+类名
*/
Class<?> cls01 = Class.forName("cn.zj.domain.Person");
System.out.println(cls01);
通过类名的属性class获取;
多用于参数的传递
Class<Person> cls02 = Person.class;
System.out.println(cls02);
getClass()在Object中定义,也就是说,所有的类的有这个方法;
多用于有对象的情况下,需要获取该对象的字节码对象。
Person person = new Person();
Class cls03 = person.getClass();
System.out.println(cls03);
结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
获取所有public修饰的成员变量
Class<Person> personClass = Person.class;
/**
* 获取所有public修饰的成员变量
*/
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
获取指定的public修饰的成员变量
Class<Person> personClass = Person.class;
/**
* 获取指定的public修饰的成员变量
*/
Field a = personClass.getField("a");
获取所有的成员变量
Class<Person> personClass = Person.class;
/**
* 获取所有成员变量
*/
Field[] declaredFields = personClass.getDeclaredFields();
for (Field field :
declaredFields) {
System.out.println(field);
}
获取指定的成员变量,不管指定的成员变量的修饰符是什么。
Class<Person> personClass = Person.class;
/**
* 获取指定的成员变量,不管是何总修饰符修饰的
*/
Field d = personClass.getDeclaredField("d");
System.out.println(d);
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);
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());
获取指定参数的public修饰的构造函数
Class<Person> personClass = Person.class;
/**
* 获取指定参数的public修饰的构造函数
*/
Constructor<Person> constructor = personClass.getConstructor(String.class, Integer.class);
System.out.println(constructor);
获取所有public修饰的构造函数
Class<Person> personClass = Person.class;
/**
* 获取所有public修饰的构造函数
*/
Constructor<?>[] constructors = personClass.getConstructors();
for (Constructor con :
constructors) {
System.out.println(con);
}
获取指定参数的构造函数,不考虑权限修饰符
Class<Person> personClass = Person.class;
/**
* 获取指定参数的构造函数,不考虑权限修饰符
*/
Constructor<Person> declaredConstructor = personClass.getDeclaredConstructor(Integer.class);
System.out.println(declaredConstructor);
获取所有的构造函数,不考虑权限修饰符
Class<Person> personClass = Person.class;
/**
* 获取所有的构造函数,不考虑权限修饰符
*/
Constructor<?>[] declaredConstructors = personClass.getDeclaredConstructors();
for (Constructor con :
declaredConstructors) {
System.out.println(con);
}
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);
获取指定名称和参数的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);
获取所有public修饰的成员方法,包含它的父类Object里的方法
Class<Person> personClass = Person.class;
/**
* 获取所有public修饰的成员方法,包含它的父类Object里的方法
*/
Method[] methods = personClass.getMethods();
for (Method method :
methods) {
System.out.println(method);
}
获取指定的成员方法,不考虑权限修饰符
Class<Person> personClass = Person.class;
/**
* 获取指定的成员方法,不考虑权限修饰符
*/
Method sing = personClass.getDeclaredMethod("sing", Integer.class);
System.out.println(sing);
获取所有成员方法,不考虑权限修饰符。不包含父类Object中的方法
Class<Person> personClass = Person.class;
/**
* 获取所有成员方法,不考虑权限修饰符。不包含父类Object中的方法
*/
Method[] declaredMethods = personClass.getDeclaredMethods();
for (Method met :
declaredMethods) {
System.out.println(met);
}
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);
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);
}
获取类名,返回为:包名+类名
Class<Person> personClass = Person.class;
//获取类名
String name1 = personClass.getName();
System.out.println("name1: "+name1);
需求描述:写一个”框架“,可以创建任意类的对象,并且执行其对象中的任意的方法。
步骤:1.读取配置文件中的内容;
2.将需要运行的类加载进内存
3.利用反射创建对象
4.利用反射获取方法
5.利用反射执行方法
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);
}
}