反射
概述
反射:将类的各个组成部分封装为其他对象,这就是反射机制
- 可以在程序运行过程中,操作这些对象
- 可以解耦,提高程序的可扩展性
获取Class对象的方式
- Class.forName(“全类名”):将字节码文件加载进内存,返回Class对象----->对应第一阶段源代码阶段
- 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
- 类名.class:通过类名的属性class获取---------->对应第二阶段 内存加载阶段
- 多用于参数的传递
- 对象.getClass():getClass()方法在Object类中定义着 ------->对应 第三阶段创建对象的运行阶段
- 多用于对象的获取字节码的方式
//获取类对象的三种方式
//1.Class.forName("全类名")
Class aClass = Class.forName("com.z.Reflect");
System.out.println(aClass);
//2.类名.class:通过类名的属性class获取
Class aClass1 = Reflect.class;
System.out.println(aClass1);
//3.对象.getClass()
Reflect reflect = new Reflect();
Class aClass2 = reflect.getClass();
System.out.println(aClass2);
System.out.println(aClass==aClass1);
System.out.println(aClass==aClass2);
结论:
同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
Class对象功能
1. 获取成员变量们 Field(成员变量)
// Field[] getFields() :获取所有public修饰的成员变量
Class personClass= Class.forName("com.z.Person");
Field[] fields = personClass.getFields();
for (Field field : fields) {
System.out.println(field);
}
System.out.println("=============");
//Field getField(String name) 获取指定名称的 public修饰的成员变量
Field field_a = personClass.getField("a");//获取成员变量a
System.out.println(field_a);
Person p = new Person();
Object value = field_a.get(p);//获取成员变量a的值
System.out.println(value);
field_a.set(p,"QQQ");//设置成员变量a的值
System.out.println(p);
System.out.println("=============");
//Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
Field[] declaredFields = personClass.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField);
}
System.out.println("=============");
//Field getDeclaredField(String name)
Field d = personClass.getDeclaredField("d");//d为私有成员变量
System.out.println(d );
//忽略访问权限修饰符的安全检查---->获取和设置私有成员变量的值
d.setAccessible(true);//暴力反射
Object value2 = d.get(p);
System.out.println(value2);
d.set(p,"WWW");
System.out.println(p);
System.out.println("=============");
另附Person类
package com.z;
public class Person {
private String name;
private int age;
public String a;
protected String b;
String c;
private String d;
public Person(String name, int age, String a, String b, String c, String d) {
this.name = name;
this.age = age;
this.a = a;
this.b = b;
this.c = c;
this.d = d;
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public Person() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getA() {
return a;
}
public void setA(String a) {
this.a = a;
}
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
public String getC() {
return c;
}
public void setC(String c) {
this.c = c;
}
public String getD() {
return d;
}
public void setD(String d) {
this.d = d;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", a='" + a + '\'' +
", b='" + b + '\'' +
", c='" + c + '\'' +
", d='" + d + '\'' +
'}';
}
public void eat(){
System.out.println("吃午饭!");
}
public void eat(String food){
System.out.println("吃午饭!食物是:"+food);
}
}
2. 获取构造方法们
//Constructor<?>[] getConstructors()
//有参构造器
Constructor constructor = personClass.getConstructor(String.class, int.class);
System.out.println(constructor);
//获取构造器之后可以创建对象
Object person = constructor.newInstance("张三", 18);//创建person对象
System.out.println(person);
//无参构造器
Constructor constructor1 = personClass.getConstructor();
Object person1 = constructor1.newInstance();
System.out.println(person1);
//简化无参生成对象
Object o = personClass.newInstance();
System.out.println(o);
//Constructor<T> getConstructor(类<?>... parameterTypes)
//Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
//Constructor<?>[] getDeclaredConstructors()
3. 获取成员方法们
//Method[] getMethods()
//Method getMethod(String name, 类<?>... parameterTypes)
Method[] methods = personClass.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//无参方法
Method eat_method = personClass.getMethod("eat");//获取eat方法
//拿到方法--->执行
eat_method.invoke(o);
//有参方法
Method eat_method2 = personClass.getMethod("eat", String.class);
eat_method2.invoke(o,"米饭");
//Method[] getDeclaredMethods()
//Method getDeclaredMethod(String name, 类<?>... parameterTypes)
4.获取全类名
//String getName()
String personClassName = personClass.getName();
System.out.println(personClassName);
反射案例
实现一个框架类–>可以创建任意对象,执行任意方法(不能改变该类的任何代码)
新建一个pro.properties资源文件
className=com.z.Student
methodName=sleep
框架类
package com.z;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;
/**
* 框架类-->可以创建任意对象,执行任意方法(不能改变该类的任何代码)
*
* 实现技术:配置文件、反射
*
* 步骤:
*1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
*2. 在程序中加载读取配置文件
*3. 使用反射技术来加载类文件进内存
*4. 创建对象
*5. 执行方法
*
*/
public class ReflectProject {
public static void main(String[] args) throws Exception{
//1.加载配置文件
//1.1创建properties对象
Properties properties = new Properties();//创建配置对象
//1.2加载配置文件,转换为一个集合
//1.2.1获取class目录下的配置文件
ClassLoader classLoader = ReflectProject.class.getClassLoader();
InputStream inputStream = classLoader.getResourceAsStream("com/pro.properties");
properties.load(inputStream);
/**
ClassLoader的作用:基本上所有的类加载器都是 java.lang.ClassLoader类的一个实例。
它是用来加载 Class 的。它负责将 Class 的字节码形式转换成内存形式的 Class 对象。
除此之外,ClassLoader还负责加载 Java 应用所需的资源,如图像文件和配置文件等
*/
//2.获取配置文件中定义的数据
String className = properties.getProperty("className");
String methodName = properties.getProperty("methodName");
//加载该类进内存
Class cls = Class.forName(className);
//创建对象
Object o = cls.newInstance();
System.out.println(o);
//获取方法对象
Method method = cls.getMethod(methodName);
//执行方法
method.invoke(o);
}
}
通过修改配置文件可以实现生成任意类的对象,并执行指定的方法