栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Reflective反射机制解析

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Reflective反射机制解析

目录

反射:框架设计的灵魂

1、类的三种获取方式

(1)、Class.forName("全类名")

 (2)、类名.class

 (3)、对象.getClass()

1.1、三种类获取方法的相同之处

Field成员变量的获取

 Constructor构造方法的获取

Merhod类里面方法的获取 

最后来个案例融会贯通一下吧


反射:框架设计的灵魂

        反射机制:将类(Class)的各个组成部分(域(Field),构造方法(Constructor),方法(Method))封装为其他对象

        功能:

在运行时分析类的能力;在运行时查看对象;实现通用的数组操作代码;可以解耦;

        为了方便理解,我们先看一下Java程序运行的三个阶段:

        第一个阶段:源码阶段,源码通常保存在硬盘上,所以第一阶段就是从硬盘上读取字节码。

        第二个阶段:内存阶段,要知道一个程序运行,并非是直接在硬盘上运行的(否则要内存条何用),而是在内存里运行的。所以第二个阶段就是通过类加载器从硬盘上把类加载到内存里。

        第三个阶段:运行阶段,这个阶段才是我们所熟悉的运行阶段。对象的创建以及方法的执行就是在这个阶段(如何运行的就要去看计算机的操作系统原理了)

而类的三种获取方法也对应这三个不同的阶段。

 

1、类的三种获取方式

        (1)、Class.forName("全类名")

        (2)、类名.class

        (3)、对象.getClass()

类的三种获取方式
方式阶段异同
Class.forName("全类名")源码阶段

         将字节码文件加载进内存(源码阶段),返回Class对象,全类名通常定义在配置文件中,便于利反射机制生成类对象,加载类。

        这个方法只有在forName是类名或者接口名才能使用,否则将抛出一个chekedException。所以无论什么时候,使用forName时都应该提供一个异常处理器

类名.class内存阶段

类加载进内存后从类名获取(内存阶段)

        想想为什么是.class而不是.class()?

        通常  类名.属性  代表什么?类的静态属性,直接通过类名调用

对象.getClass()运行阶段这个就比较容易理解,通过对象获取该对象的类。而对象是在(运行阶段)创建的。

(1)、Class.forName("全类名")

        将字节码文件加载进内存(源码阶段),返回Class对象,全类名通常定义在配置文件中,便于利反射机制生成类对象,加载类。

这个方法只有在forName是类名或者接口名才能使用,否则将抛出一个chekedException。所以无论什么时候,使用forName时都应该提供一个异常处理器

 (2)、类名.class

        类加载进内存后从类名获取(内存阶段)

        想想为什么是.class而不是.class()?

        通常  类名.属性  代表什么?类的静态属性,直接通过类名调用

 (3)、对象.getClass()

        这个就比较容易理解,通过对象获取该对象的类。而对象是在(运行阶段)创建的。

1.1、三种类获取方法的相同之处
public class test {
    public static void main(String[] args) throws Exception {
        Person person = new Person();
        Class aClass = Class.forName("reflective.Person");
        Class personClass = Person.class;
        Class aClass1 = person.getClass();

        if (aClass == personClass && personClass == aClass1) {
            System.out.println("三个方法获取的是同一个地址");
        }

    }
}

 输出结果:

        三个方法获取的是同一个地址

 由此可见,三种方法应用的都是同一个地址。

Field成员变量的获取

        获取到类之后的第二步就是获取成员属性

获取成员变量的四种方法
Filed[] getFileds()返回所有public修饰的成员变量(只能用于public关键字)
Filed[] getFiled(String filedName)返回特定public修饰的成员变量(只能用于public关键字)
Filed[] getDeclaredFields()返回所有变量,不考虑修饰符
Filed[] getDeclaredField(String filedName)返回特定的成员变量,获取私有属性时关键字安全检查机制可能会报异常,这时候就要用到setAccessible(true);来忽略安全检查了,这步骤也叫暴力反射

import java.lang.reflect.Field;



public class ReflectDemo1 {
    public static void main(String[] args) throws Exception {
        //获取person的class对象
        Class personClass = Person.class;

        //Filed[] getFileds()是用来返回所有public修饰的成员变量
        Field[] fields = personClass.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }

        System.out.println("---------------");
        Field a = personClass.getField("a");
        Person person = new Person();
        System.out.println(a.get(person));
        //设置a的值
        a.set(person,"张三");
        System.out.println(person);

        System.out.println("=============");
        //Filed[] getDeclaredFields() 获取所有变量,不考虑修饰符
        Field[] declaredFields = personClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            System.out.println(declaredField);
        }

        //Filed
        Field declaredField = personClass.getDeclaredField("d");
        //忽略访问修饰符的安全检查
        declaredField.setAccessible(true); //暴力反射
        Object value = declaredField.get(person);
        System.out.println(value);

    }
}

 Constructor构造方法的获取

        获取了成员属性后就是获取类的构造方法了

       使用 Constructor getConstructor(Class...) 获取构造方法

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;



public class ReflectGetConstructor {
    public static void main(String[] args) throws Exception {
        //获取person的class对象
        Class personClass = Person.class;

        //Constructor getConstructor(Class...)
        Constructor constructor = personClass.getConstructor(String.class, int.class);
        System.out.println(constructor);
        //使用获取到的构造方法创建对象
        Object person1 = constructor.newInstance("Sun", 23);
        System.out.println(person1);

    }
}

Merhod类里面方法的获取 

        最后一步就是方法的获取了,取得一个类功能的关键性一步

        获取方法:对象.getMethod("类名");



public class ReflectGetMethod {
    public static void main(String[] args) throws Exception{
        Class personClass = Person.class;

        //personClass.getMethod
        Method eat_method = personClass.getMethod("eat");
        Person person = new Person();
        //执行方法
        eat_method.invoke(person);
        Method eat_method2 = personClass.getMethod("eat", String.class);
        eat_method2.invoke(person,"饭");
        System.out.println(eat_method2.invoke(person,"粥"));

        //获取所有的public方法
        Method[] methods = personClass.getMethods();
        for (Method method : methods) {
            System.out.println(method);
            //获取方法名
            String name = method.getName();
            System.out.println(name);
            //method.setAccessible(ture)
        }

        //获取类名
        String className = personClass.getName();
        System.out.println(className);

    }
}

最后来个案例融会贯通一下吧

        测试类:

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



public class ReflectTest {
    public static void main(String[] args) throws Exception {
        //可以创建任意的对象,可以创建按任意的方法

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

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

        //3.使用加载技术来加载类文件进内存
        Class aClass = Class.forName(clessName);
        //4.创建对象
        Object o = aClass.newInstance();
        //5.获取方法对象
        Method method = aClass.getMethod(methodName);

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


    }
}

新建个Student类,类里面有一个sleep方法

新建一个配置文件 pro.roperties

        以后创建的对象以及调用的方法就直接在配置文件里操作就可以啦!

className = reflective.student.Student
methodName = sleep

来一个运行结果来奖励一下自己

 

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/754714.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号