反射的使用

1、基本概念

框架:半成品软件。可以在框架的基础上进行软件开发,达到简化代码的目的。
反射:将类的各个部分封装为其他对象进行使用。
反射优点:
1 可以在程序运行过程中操作这些对象。
2 可以解耦、提高程序的可扩展性。

2、获取Class对象的方式

2.1 Class.forName()

功能:将字节码文件加载到内存中,返回Class对象。
格式:Class 变量名 = Class.forName(类路径);
示例:Class person_class1 = Class.forName(“domain.Person”);
用途:多用于配置文件,将类名定义在配置文件中,用于读取文件加载类。
注意事项:该方式存在ClassNotFoundException异常,需要throws或者try catch

2.2 类名.class

功能:通过类名的class属性获取class对象。
格式:Class 变量名 = 类名.class;
示例:Class person_class2 = Person.class;
用途:多用于参数的传递。

2.3 对象名.getClass()

功能:通过对象的getClass()方法获取Class对象。
格式:Class 变量名 = 对象名.getClass();
示例:
Person p = new Person();
Class person_class3 = p.getClass();
用途:多用于对象的获取字节码的方式。

2.4 Class对象.newInstance()

功能:用于创建类对象。
使用格式:Object 对象名 = Class对象.newInstance()
示例:Object o1 = c1.newInstance();
注意事项:调用此方法创建的类对象,构造方法为空参构造方法,如需创建有参数的构造方法,则需要通过Constructor对象创建。

3、通过Class对象获取的Field对象及Field对象的使用

3.1 基本概念

Field对象:用于表示类中成员变量的对象,需要通过Class对象的方法获取。

3.2 获取Field对象的方法

3.2.1、getFields()
功能:获取所有public修饰的成员变量对象。
使用格式:Field[] 变量名 = Class对象名.getFields();
示例:Field[] person_all_public_field = person_class.getFields();
3.2.2、getField(String name)
功能:获取指定名称的public修饰的成员对象。
使用格式:Field 变量名 = Class对象名.getField(成员变量名称);
示例:Field person_a_field = person_class.getField(“a”);
3.2.3、getDeclaredFields()
功能:不考虑修饰符获取所有的成员变量。
使用格式:Field[] 变量名 = Class对象名.getDeclaredFields();
示例:Field[] person_all_field = person_class.getDeclaredFields();
3.2.4、getDeclaredField(String name)
功能:不考虑修饰符获取指定名称的成员变量。
使用格式:Field 变量名 = Class对象名.getDeclaredField(成员变量名称)
示例:Field person_age_field = person_class.getDeclaredField(“age”);

3.3 Field对象常用的方法

3.3.1、setAccessible(boolean b)
功能:当获取到的成员变量是使用private修饰的时,可以使用该方法确定成员变量是否可以被处理,当参数为true时表示可以被处理,
为false时不能被处理。
使用格式:Field对象名.setAccessible(boolean b);
示例:person_age_field.setAccessible(true);
3.3.2、get()
功能:获取Field对象(即成员变量)的值。
使用格式:Object 变量名 = Field对象名.get(成员变量所属的对象);
示例:Object o = person_age_field.get§;
3.3.3、set()
功能:给Field对象(即成员变量)赋值。
使用格式:Field对象名.set(成员变量所属的对象,成员变量值)
示例:person_age_field.set(p, 15);

4、通过Class对象获取Constructor对象及Constructor对象的使用

4.1 基本概念

Constructor对象:用于表示类中构造方法的对象,需要通过Class对象获得。

4.2 获取Constructor对象的方法

4.2.1、getConstructors()
功能:获取类中的所有构造方法。
使用格式:Constructor[] 变量名 = Class对象名.getConstructors();
示例:Constructor[] person_constructors = person_class.getConstructors();
4.2.2、getConstructor()
功能:根据参数获取类中指定的构造方法。
使用格式:Constructor 变量名 = Class对象名.getConstructor(数据类型.class(与构造方法中的参数相同))
示例:Constructor person_constructor1 = person_class.getConstructor(String.class, int.class);

4.3、Constructor对象常用的方法

4.3.1 newInstance()
功能:用于创建构造方法表示的类对象。
使用格式:Object 变量名 = Constructor对象名.newInstance(根据所表示的构造方法传递参数);
示例:Object o1 = person_constructor1.newInstance(“张三”, 30);
注意事项:此时创建的对象还不能使用类中的成员变量和成员方法,需要强制类型转换为具体的类对象才能使用。
4.3.2、setAccessible(boolean b)
功能:用于暴力反射,即不论构造方法是使用什么修饰符修饰的都能对Constructor对象的方法进行处理,
当参数为true时表示可以被处理,为false时不能被处理。
使用格式:Constructor对象名.setAccessible(boolean b);
示例:person_constructor.setAccessible(true);

5、通过Class对象获取Method对象及Method对象的使用

5.1 基本概念

Method对象:用于表示类对象方法的对象,通过Class对象获取。

5.2 获取Method对象的方法

5.2.1、getMethods()
功能:获取类对象中所有的方法。
使用格式:Method[] 对象名 = Class对象名.getMethods()
示例:Method[] person_methods = person_class.getMethods();
注意事项:
1、getMethods方法获取的方法包含类中定义的方法和关联的方法。
5.2.2、getMethod()
功能:获取指定的类对象方法,参数中传递方法名称和方法中参数的数据类型.class。
使用格式:Method 变量名 = Class.getMethod(方法名称, 方法参数数据类型.class);
示例:Method person_method1 = person_class.getMethod(“getAge”);

5.3 Method对象常用的方法

5.3.1、getName()
功能:获取Method对象表示方法的名称。
使用格式:String 变量名 = Method对象.getName();
示例:String method1_name = person_method1.getName();
5.3.2、invoke()
功能:执行Method对象表示的方法。
使用格式:Object 变量名 = Method.invoke(类对象);
示例:Object age = person_method1.invoke§;

6、反射的使用步骤

1、创建一个输入流对象读取配置文件,输入流对象可以是字节流对象也可以是字符流对象。
2、创建Properties对象,然后调用对象的load方法导入配置文件。
3、调用Properties对象的getProperty()方法获取配置信息。
4、根据配置信息创建Class对象将类加载到内存中。
5、调用Class对象的方法获取类的构造方法对象。
6、调用构造方法对象的newInstance方法创建类对象。
7、根据配置信息调用Class对象获取方法对象。
8、调用方法对象的invoke()方法执行类对象对应的方法。
使用示例:
使用的类

package domain;

public class Person {
    private String name;
    private int age;
    public String a;
    public String b;

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    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;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", a='" + a + '\'' +
                ", b='" + b + '\'' +
                '}';
    }

    public void eat(){
        System.out.println(this.name + "正在吃午饭");
    }
}

配置文件:

ClassName = domain.Person
EatMethod = eat
SetNameMethod = setName
GetNameMethod = getName

使用方法:

package reflect;

import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;

/**
 * 功能:练习反射的使用
 */
public class TestReflect {
    public static void main(String[] args) throws Exception {
        // 1、加载配置文件
        // 1.1 创建Properties对象
        Properties p = new Properties();
        // 1.2 加载配置文件转换为一个集合
        // ClassLoader classLoader = TestReflect.class.getClassLoader();
        // InputStream is = classLoader.getResourceAsStream("reflect\\pro.properties");
        FileInputStream is = new FileInputStream("src\\reflect\\pro.properties");
        //FileReader is = new FileReader("src\\reflect\\pro.properties");
        p.load(is);
        // 2、获取配置文件中的数据
        String class_name = p.getProperty("ClassName");
        String eat_method = p.getProperty("EatMethod");
        String set_name_method = p.getProperty("SetNameMethod");
        String get_name_method = p.getProperty("GetNameMethod");
        // 3、根据配置文件将类加载到内存中
        Class c1 = Class.forName(class_name);
        // 4、获取构造方法创建类对象
        //Object o1 = c1.newInstance();
        Constructor class_constructor = c1.getConstructor(String.class, int.class);
        Object o1 = class_constructor.newInstance("张三", 30);
        // 5、获取对象方法
        Method eat = c1.getMethod(eat_method);
        Method set_name = c1.getMethod(set_name_method, String.class);
        Method get_name = c1.getMethod(get_name_method);

        // 6、执行方法
        eat.invoke(o1);
        set_name.invoke(o1,"李四");
        Object name = get_name.invoke(o1);
        System.out.println(name);
        eat.invoke(o1);
    }
}