zoukankan      html  css  js  c++  java
  • 反射

    反射

    1、java代码在计算机中的三个阶段:

    **× 源代码阶段 ×--------------->× Class 类对象 ×----------------> × Runtime阶段 **

    第一阶段:java源代码,java字节码阶段,这个的Java程序还是在硬盘上

    第二计算:通过类加载器(ClassLoader)将字节码文件加载到内存,在内存中用Class类对象来表示Java程序,该Class对象主要包含三个对象,描述成员变量的Filed[]、描述构造方法的Constructor[]、描述成员方法的Method[]。注意到他们都是对象数组,这是因为一个类可能有个多个成员变量,多个构造方法,多个成员方法。反射机制就是将类的这几个部分封装为Field、Constructor、Method对象。

    2、获得字节码文件对象(class对象)方式

    • Class.forName(“全类名”)静态方法,参数是全类名(包名.类名,将字节码文件加载进内存,返回Class对象,多用于配置文件,类名一般定义在配置文件中,读取文件,加载类
    • 通过类名的属性Class获取:类名称.class,多用于参数的传递
    • 通过对象的方法getClass(),这个方法是在Object类中定义的:对象名.getClass()

    注意:其实同一个字节码文件在一次程序的运行过程中只会被加载一次,也就是如果是在同一种程序中,无论使用上面的哪一种方法获取字节码文件对象,都是返回的同一个字节码对象,都是在相同的内存位置。

    比如要获得Person类的class对象

    Class<Person> personClass = Person.class;
    

    3、Class对象的功能

    无论是成员变量,构造方法,方法,都有一个setAccessible(true);调用这个方法,支持暴力反射(忽略权限修饰符的安全检查),使得可以访问获得的私有(private)修饰的方法,成员变量等,否则就会抛出异常

    • 获取成员变量们
    方法 描述
    Fileds[] getFileds() 返回所有由public修饰的成员变量的对象组成的数组
    Field getFiled(String name) 返回指定的由public修饰的成员变量的对象
    Fields[] getDeclaredFields() 返回所有成员变量的对象的数组,无论修饰符是什么
    Field getDeclaredField(String name) 返回指定的成员变量的对象,无论修饰符是什么
    package cn.zhuobo.reflect;
    
    import java.lang.reflect.Array;
    import java.lang.reflect.Field;
    import java.util.Arrays;
    
    public class Demo01 {
        public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
            //
            Class<Person> personClass = Person.class;
    
            Field[] fields = personClass.getFields();
    
            System.out.println(Arrays.toString(fields));
            // 拿到的其中一个成员变量StringB name的对象
            Field name = personClass.getField("name");
    
            Person p = new Person();
    
            // get,获取成员变量的值
            Object o = name.get(p);// 传递一个对象,要获得这个对象的成员变量的值
            System.out.println(o);// 这样就获取了成员变量的值
    
            //设置成员变量的值
            name.set(p, "zhuobo");// 传递两个参数,第一个是要设置成员变量值的对象,第二个是他的值
            System.out.println(p);
    
            Field s = personClass.getDeclaredField("s");
            s.setAccessible(true);// 调用这个方法,暴力反射(忽略权限修饰符的安全检查),使得可以访问获得的私有(private)成员变量,否则就会抛出异常
            Object o1 = s.get(p);
            System.out.println(o1);
    
        }
    }
    
    • 获取构造方法
    方法 描述
    Constructor<?>[] getConstructors() 获取所有的构造方法
    Constructor getConstructor(类<?>....参数列表) 获取特定的构造方法
    Constructor<?>[] getDeclaredConstructors()
    Constructor[] getDeclaredConstructor(类<?>....参数列表)

    用来获取构造方法,获得构造方法后调用方法newInstance(参数列表)创建对象,如果是无参数的构造方法,其实也可以使用Class对象的newInstance方法创建对象。

    package cn.zhuobo.reflect;
    
    import java.lang.reflect.Constructor;
    
    public class Demo02Constructor {
        public static void main(String[] args) throws Exception {
            Class<Person> personClass = Person.class;
            // get all costructor
            Constructor<?>[] constructors = personClass.getConstructors();
            for (Constructor<?> constructor : constructors) {
                System.out.println(constructor);
            }
            // get a constructor for given fields
            Constructor<Person> constructor = personClass.getConstructor(String.class, int.class);
            System.out.println(constructor);
    
            // use the method newInstance() to creat a object
            Person person = constructor.newInstance("猪八戒", 367);
            System.out.println(person);
    
            // construct a object without param
            Constructor<Person> constructor1 = personClass.getConstructor();
            Person person1 = constructor1.newInstance();
            System.out.println(person1);
    
            // 创建无参数对象的另一种方法
            Person person2 = personClass.newInstance();
            System.out.println(person2);
        }
    }
    
    • 获取成员方法
    方法 描述
    Method[] getMethods() 获取所有public修饰的成员方法,还包括继承自父类Object的方法,wait、notify、hashCode等方法
    Method getMethods(String name, 类<?>...参数类型) 获取特定的构造方法
    Method[] getDeclaredMethods()
    Method getDeclaredMethod(String name, 类<?>...参数类型)
    package cn.zhuobo.reflect;
    
    import java.lang.reflect.Method;
    
    public class Demo03Method {
        public static void main(String[] args) throws Exception {
            Class<Person> personClass = Person.class;
    
            //获得并调用带参数的方法
            Method say = personClass.getMethod("say", String.class);
            Person p = new Person("蜘蛛侠",369);
            say.invoke(p, "chifanfa");
    
            // 获得并调动空参数的方法
            Method say1 = personClass.getMethod("say");
            say1.invoke(p);
    
            Method[] methods = personClass.getMethods();
            for (Method method : methods) {
                //System.out.println(method);
                System.out.println(method.getName());// 用来获取方法名的getName
            }
        }
    }
    
    • 获取类名
    String getName()
    

    4、反射的一个应用

    在还没有知道要使用什么类,使用什么类的什么方法的时候,可以在运行是才决定具体是使用什么了什么方法。看起来好炫的样子,什么都不知道就可以用了。可以利用放射机制可以在某些途径获得要使用的类,要使用的方法。

    1. 创建一个pro.properties配置文件,文件里面定义要使用的类的名称以及方法(当代码想要使用不同的类,就修改这个配置文件就可以了,不用修改代码)

      • 使用全类名的配置文件,这种情况下,代码回调用Student的eat方法

        className=cn.zhuobo.reflect.Student
        methodName=eat
        
      • 这种情况下,调用Person类的say方法

        className=cn.zhuobo.reflect.Person
        methodName=eat
        
    2. 使用反射的过程

      package cn.zhuobo.reflect;
      
      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 {
              // 创建Properties对象
              Properties properties = new Properties();
      
              // 获取配置文件,使用类加载器
              ClassLoader classLoader = ReflectTest.class.getClassLoader();
              InputStream is = classLoader.getResourceAsStream("pro.properties");
              properties.load(is);
      
              // 获取配置文件中定义的数据
              String className = properties.getProperty("className");
              String methodName = properties.getProperty("methodName");
      
              // 获取对象,创建对象
              Class aClass = Class.forName(className);
              Object o = aClass.newInstance();
      
              //获取方法,调用方法
              Method method = aClass.getMethod(methodName);
              method.invoke(o);
      
          }
      }
      
  • 相关阅读:
    JavaScript 编程艺术-第4章(JavaScript美术馆)代码
    Python——nose实例示例
    Python测试工具——nose
    Pycharm安装及第一次使用导航
    ALV常用参数详细描述
    sap去除后缀0方法
    FM四舍五入_从小数点最后一位进位
    SAP 使用较频繁的日期时间处理函数总结
    python基础--time和datetime模块
    python基础--模块使用
  • 原文地址:https://www.cnblogs.com/zhuobo/p/10675831.html
Copyright © 2011-2022 走看看