JAVA反射

什么是反射

反射是指在程序运行状态下,不仅可以获取任意类的成员变量(Fields)、成员方法(Methods)、构造方法(Constructors)等信息,还能够动态创建Java类的实例(newInstance)、调用任意类方法(invoke)、修改任意类成员变量值等。JAVA反射机制是JAVA被视为动态语言的关键特性,同时也是JAVA各类框架底层实现的灵魂。

获取Class类对象的三种方法:

  1. Class.forName(“全类名”);
    将字节码文件加载进内存,返回class对象
    多用于配置文件,将类名定义在配置文件中。读取文件,加载类
  2. 类名.class
    通过类名的属性class获取
    多用于参数的传递
  3. 对象.getClass()
    getclass()方法在object类中定义的
    多用于对象获取字节码的方式

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过以上三种哪一种方式获取的class对象都是同一个。

案例:

public class ReflectionTest {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.Class.forName("全类名")
        Class cls1 = Class.forName("Reflection.User");
        System.out.println(cls1);
        //2.类名.class
        Class cls2 = User.class;
        System.out.println(cls2);
        //3.对象.getClass()
        User user = new User();
        Class cls3 = user.getClass();
        System.out.println(cls3);

        //比较三个对象 
        System.out.println(cls1 == cls2);
        System.out.println(cls1 == cls3);
        /*
        * 结论:
        * 同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次
        * 不论通过哪一种方式获取的Class对象都是同一个
        * */
    }
}

运行结果:
JAVA反射_第1张图片

反射的基础类和方法

类名 用途
Class类 代表类的实体,在运行的Java应用程序中表示类和接口
Field类 代表类的成员变量(成员变量也称为类的属性)
Method类 代表类的方法
Constructor类 代表类的构造方法
  1. 获取成员变量们
    ● getFields() - 返回该类及其超类的所有公共字段
    ● getDeclaredFields() - 返回类的所有字段
    ● getModifier() - 以整数形式返回字段的修饰符
    ● set(classObject,value) - 使用指定的值设置字段的值
    ● get(classObject) - 获取字段的值
    ● setAccessible(boolean) - 使私有字段可访问setAccessible(true)
    注意:如果我们知道字段名称,则可以使用
    ● getField(“fieldName”) - 从类返回名称为fieldName的公共字段。
    ● getDeclaredField(“fieldName”) - 从类返回名称为fieldName的字段。
  2. 获取构造方法们
    ● getConstructors() - 返回该类的所有公共构造函数以及该类的超类
    ● getDeclaredConstructor() -返回所有构造函数
    ● getName() - 返回构造函数的名称
    ● getModifiers() - 以整数形式返回构造函数的访问修饰符
    ● getParameterCount() - 返回构造函数的参数数量
  3. 获取成员方法们
    ● getMethods() - 返回该类及其超类的所有公共方法
    ● getDeclaredMethod() - 返回该类的所有方法
    ● getName() - 返回方法的名称
    ● getModifiers() - 以整数形式返回方法的访问修饰符
    ● getReturnType() - 返回方法的返回类型
  4. 获取类名
    ● getName() - 返回方法的名称

“框架”的简单搭建

无反射,无框架
案例:

FrameworkDemo
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class FrameworkDemo {
    public static void main(String[] args) throws Exception {
        //可以创建任意类的对象,执行任意方法
        //        User user = new User();
        //        user.eat();
        /*
        * 前提:不改变类的任何代码,创建类的任意对象,执行任意方法
        * */

        //1.加载配置文件
        //1.1 创建Properties对象
        Properties properties = new Properties();
        //1.2 加载配置文件,转换为一个集合
        //1.2.1 获取class目录下的配置文件
        ClassLoader classLoader = FrameworkDemo.class.getClassLoader();//获取类加载器
        InputStream resourceAsStream = classLoader.getResourceAsStream("pro.properties");
        properties.load(resourceAsStream);

        //2.获取配置文件中定义的数据
        String className = properties.getProperty("className");
        String methodName = properties.getProperty("methodName");

        //3.加载该类进内存
        Class aClass = Class.forName(className);

        //4.类的实例化
        Object o = aClass.newInstance();

        //5.获取方法对象
        Method method = aClass.getMethod(methodName);

        //6.执行方法
        method.invoke(o);


    }
}

User

public class User {
    public String name;
    private int age;

    public User() {
    }

    public User(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 "User{" +
        "name='" + name + '\'' +
        ", age=" + age +
        '}';
    }
    public void eat(){
        System.out.println("吃饭");
    }
    public void eat(String food){
        System.out.println("吃"+food);
    }


}

pro.properties

className=Reflection.User
methodName=eat

代码结构
JAVA反射_第2张图片

运行结果:
JAVA反射_第3张图片

可以看出FrameworkDemo中的代码完全可以用两行代码替换

User user = new User();
user.eat();

为何又要使用那么冗余的代码编写呢?
其实这就是Java被视为动态语的关键,在不改变原有代码,只改变配置文件内容或设置用户可控参数,即可实现任意类的实例化以及方法调用。以上两行代码只是Java静态语言的编写,即程序一旦运行便不可改变。

你可能感兴趣的:(编程语言,java,开发语言)