• 反射与类对象获取-Java学习


    原文地址:https://www.cnblogs.com/imdeveloper/p/11787310.html

    类对象

    类对象指的是一个类在jvm中加载后所形成的对象,每一个类都只有一个类对象,该类对象被所有的实例对象所共享。

    类之间有不同的方法,不同的属性。类对象,就是用于描述这种类,都有什么属性,什么方法的。

    获取类对象有三种方式:

    1. Class.forName
    2. Hero.class
    3. new Hero().getClass()
    Class pClass1 = Class.forName(className);
    Class pClass2 = Hero.class;
    Class pClass3 = new Hero().getClass();
    

    一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的(一个ClassLoader下,一种类只会有一个类对象存在。通常一个JVM下,只会有一个ClassLoader

    获取类对象的时候,会导致类属性被初始化

    无论什么途径获取类对象,都会导致静态属性被初始化,而且只会执行一次。(除了直接使用 Class c = Hero.class 这种方式,这种方式不会导致静态属性被初始化)

    反射

    与传统的通过new来获取对象的方式不同,反射机制,会先拿到“类对象”,然后通过类对象获取“构造器对象”,再通过构造器对象创建一个对象

    //传统的使用new的方式创建对象
    Hero h1 =new Hero();
    h1.name = "teemo";
    System.out.println(h1);
      
    try {
        //使用反射的方式创建对象,要加包名
        String className = "charactor.Hero";
        //类对象
        Class pClass = Class.forName(className);
        //构造器
        Constructor c = pClass.getConstructor();
        //通过构造器实例化
        Hero h2 = (Hero) c.newInstance();
        h2.name ="gareen";
        System.out.println(h2);
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    通过反射修改属性的值

    1. 为了访问属性,把name修改为public。
      因为对于private修饰的成员,需要使用field.setAccessible(true)才能访问和修改
    2. 访问并修改
    Hero h =new Hero();
    //使用传统方式修改name的值为garen
    h.name = "garen";
    try {
        // 获取类Hero的名字叫做name的字段
        Field f1 = h.getClass().getDeclaredField("name");
        // 修改这个字段的值
        // 第一个参数是指定方法所属的实例,同一个类可能有不同属性的实例所以需要指定一下,后面的参数是方法原本需要的参数
        f1.set(h, "teemo");
        //打印被修改后的值
        System.out.println(h.name);
         
    } catch (Exception e) {
        e.printStackTrace();
    }
    
    • getField 只能获取public的,包括从父类继承来的字段。
    • getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。

      这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true)

    通过反射调用方法

    1. 首先为Hero的name属性,增加setter和getter
    2. 通过反射机制调用Hero的setName
    Hero h = new Hero();
    try {
        // 获取这个名字叫做setName,参数类型是String的方法(找不到对应参数方法会报错)
        Method m = h.getClass().getMethod("setName", String.class);
        // 对h对象,调用这个方法
        m.invoke(h, "盖伦");
        // 使用传统的方式,调用getName方法
        System.out.println(h.getName());
    
    } catch (Exception e) {
        e.printStackTrace();
    }
    

    反射方式的好处

    使用反射方式,首先在src目录下准备一个配置文件,里面存放的是类的名称,和要调用的方法名。在测试类Test中,首先取出类名称和方法名,然后通过反射去调用这个方法。

    配置

    class = reflection.Service1
    method = doService1
    

    使用

    //从spring.txt中获取类名称和方法名称
    File springConfigFile = new File("e:\project\j2se\src\spring.txt");
    Properties springConfig = new Properties();
    springConfig.load(new FileInputStream(springConfigFile));
    String className = (String) springConfig.get("class");
    String methodName = (String) springConfig.get("method");
     
    //根据类名称获取类对象
    Class clazz = Class.forName(className);
    //根据方法名称,获取方法对象
    Method m = clazz.getMethod(methodName);
    //获取构造器
    Constructor c = clazz.getConstructor();
    //根据构造器,实例化出对象
    Object service = c.newInstance();
    //调用对象的指定方法
    m.invoke(service);
    

    当需要从调用第一个业务方法,切换到调用第二个业务方法的时候,不需要修改一行代码,也不需要重新编译,只需要修改配置文件,再运行即可。

  • 相关阅读:
    HDFS API
    Wrong FS: hdfs://xxx/xxx expected: file:///
    Sqoop拒绝连接错误
    MySQL设置远程连接
    Eclipse远程连接Hadoop
    Hadoop创建新用户
    Nutch的安装和配置
    NameNode重新格式化以后DataNode不能启动
    Pig拒绝连接错误
    Pig jline.Terminal错误
  • 原文地址:https://www.cnblogs.com/imdeveloper/p/11787310.html
Copyright © 2020-2023  润新知