• Java进阶——反射


    引入

    动态编程语言

    变量并不是在计算机内存中被写入的某个值,它们只是指向内存的“标签”和“名称”,所以动态编程语言的变量没有一个固定的类型。Python

    静态编程语言

    静态编程语言的变量有固定的类型,它们指的是内存中的值。Java、C、C++

    介绍

    反射机制

    动态获取信息以及动态调用对象方法的功能。

    提供的功能

    • 运行时,判断任意一个对象所属类
    • 运行时,构造任意一个类的对象
    • 运行时,判断任意一个类所具有的成员方法和变量
    • 运行时,调用任意一个对象的方法
    • 生成动态代理

    反射机制原理

    RTTI 运行时类型信息

    运行期间,Java通过Class对象记录每个对象RTTI,当编写并编译一个新类时,就会产生一个Class对象。

    Class对象是在加载类时由JVM构造的,JVM为每个类管理一个独一无二的Class对象。

    动态的生成字节码(.class文件),加载到JVM中运行。

    使用的类

    Class类

    Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
    实例表示正在运行的Java应用程序中的类和接口。
    获取Class对象:

    • Object.getClass();
    • Class.getSuperClass();
    • Class.forName();
    • 对于包装器类型:类名.TYPE属性。

    Field类

    提供有关类和接口的属性信息,以及对其动态访问权限。

    Constructor类

    提供类的单个构造方法信息,以及对其的访问权限。

    Method类

    提供类和接口单独的某个方法的信息。

    功能使用

    获取对象的类

    • getClass()
      //1.1 getClass()
      //获取对象的类
      String str = "hello world!";
      cls = str.getClass();
      System.out.println(cls.getName());
      
    • Class.forName()
      • 类加载器加载方法
      //1.2  Class.forName();
      //根据具体包名来获取类
      //字符串合法命名是类的命名空间和类的名称组成
      cls = Class.forName("reflectprj.Student");
      

    获取类的父类

    • Class对象且该对象有父类
      //1.3 getSuperclass();
      //获取类的父类
      Class superCls = cls.getSuperclass();
      

    获取类的构造方法

    • 获取全部的构造方法getDeclaredConstructors()
    • 获取特定的构造方法getDeclaredConstructor(Class[] class)
    • 创建构造方法创建实例newInstance(参数)
      //3.1 getDeclaredConstructors();
      //获取类的构造方法
      Constructor[] constructors;
      constructors = cls.getDeclaredConstructors();
      for(Constructor constructor:constructors) {
            System.out.println(constructor.toString());
      }
      //3.1.2 
      //获取类特定的构造方法
        
      Class[] var = {int.class,String.class,String.class};
      Constructor constructor = cls.getDeclaredConstructor(var);
      System.out.println(constructor.toString());
        		
      //4.1 newInstance();
      //通过构造方法创建实例
      Student stu = (Student)constructor.newInstance(1,"王小明","man");
      System.out.println(stu.toString());
      

    获取类的方法

    • 获取全部的方法getDeclaredMethods()
    • 获取特定的方法getDeclaredMethod("方法名",Class[])
    • 将对象与方法关联,并调用方法。invoke(对象名,参数)
    • 如果方法为私有,则调用method.setAccessible(true)
      //3.2 getDeclaredMethod();
      //获取类的方法
      Method [] ms = cls.getDeclaredMethods();
      for(Method m:ms) {
          System.out.println(m.getName());
      }
      
      //4.2 invoke();
      //调用类的方法
      Method m = cls.getDeclaredMethod("setSex", String.class);
      m.invoke(stu, "women");
      System.out.println(stu.toString());
      
      //5 setAccessible()
      //调用私有方法
      m = cls.getDeclaredMethod("print", null);
      m.setAccessible(true);
      m.invoke(stu,null);
      

    获取类的属性

    • 获取全部的属性getDeclaredFields()
    • 获取特定的属性getDeclaredField("fieldName")
    • 将对象与属性关联,并设置属性set(对象名,属性)
    • 将对象与属性关联,获取属性get(对象名)
    • 如果属性为私有,则调用method.setAccessible(true)
      //3.3 getDeclaredField()
      //获取类的属性
      Field fs[] = cls.getDeclaredFields();
      for(Field f:fs) {
            System.out.println(f.getName());
      }
      
      //4.3 set();
      //设置私有类属性
      Field f = cls.getDeclaredField("sex");
      f.setAccessible(true);
      f.set(stu,"men");
      System.out.println(f.get(stu).toString());
      

    反射的应用

    操作数据库

    动态创建SQL语句。

    public void save(Object obj) {
          String sql = "insert into ";
          try {
                Class cls = obj.getClass();
                String clsName = cls.getSimpleName();
                sql+=clsName;
                sql+="(";
                Field fs[] = cls.getDeclaredFields();
                for(Field f:fs) {
                      sql+=f.getName()+",";
                }
                sql = sql.substring(0, sql.length()-1);
                sql+=") values(";
                Field fs1[] = cls.getDeclaredFields();
                for(Field f:fs1) {
                      f.setAccessible(true);
                      sql+=f.get(obj)+",";
                }
                sql = sql.substring(0, sql.length()-1);
                sql+=")";
          }catch(Exception e) {
                e.printStackTrace();
          }
          System.out.println(sql);
    }
    

    解析XML

    解析XML动态生成对象。(Spring框架)

    动态代理

    动态代理

    框架使用

    • Spring框架
    • Hibernate框架
    • Struts框架

    缺点

    反射对于性能有影响,反射基本上是一种解释操作。
    可以告诉JVM希望做什么,让其满足要求。
    这类操作慢于直接执行相同的操作。

  • 相关阅读:
    其他魔术方法
    类型约束和类的魔术常量
    PHP对象遍历、内置标准类与数据转对象
    类的自动加载与对象的克隆
    PHP重载与接口
    面向对象
    PHP基础
    地下城与勇士的项目整理
    mysql建表
    jQuery
  • 原文地址:https://www.cnblogs.com/occlive/p/reflect.html
Copyright © 2020-2023  润新知