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希望做什么,让其满足要求。
这类操作慢于直接执行相同的操作。

原文地址:https://www.cnblogs.com/occlive/p/reflect.html