美文网首页
反射知识的理解

反射知识的理解

作者: 须臾之北 | 来源:发表于2018-07-18 22:34 被阅读6次

反射

本文参考自:https://blog.csdn.net/sinat_38259539/article/details/71799078#commentBox

一、反射概述

  1. 能够分析类能力的程序称为反射
  1. JAVA反射机制是在运行状态中:
    • 对于任意一个类,都能够知道这个类的所有属性和方法;
* 对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
* 要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类中的方法.所以先要获取到每一个字节码文件对应的Class类型的对象.
  1. 反射就是把java类中的各种成分映射成一个个的Java对象

    • 例如:一个类有:成员变量、方法、构造方法、包等等信息
    • 利用反射技术可以对一个类进行解剖,把个个组成部分映射成一个个对象。
    • (其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)
    • 如图是类的正常加载过程:反射的原理在与class对象。
    • 熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
    image
  2. 若要学习反射,必须了解Class类

二、Class类

  • Class 类的实例表示正在运行的 Java 应用程序中的类和接口。
* 也就是jvm中有N多的实例每个类都有该Class对象。(包括基本数据类型)
  • Class 没有公共构造方法。
  • Class 对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的defineClass 方法自动构造的。也就是这不需要我们自己去处理创建,JVM已经帮我们创建好了。

返回Class类型实例

  1. Object类中的getClass()方法

     Employee e;
     Class c1 = e.getClass();  //获取到Employee类
    
     /*
         此时还有一个常用的方法getName()
     */
     System.out.println(c1.getName());
    
  2. T.class(),此时T为任意的java类型

     Class c1 = Random.class;
     Class c2 = int.class;
     Class c3 = Double[].class;
    
  3. 通过Class类中的static方法forName()

     String className = "java.util.Random";
     
     try{
         Class c1 = Class.forName(className);
         System.out.println(c1.getName());
     }
     catch(ClassNotFoundException e){
         e.getMessage();     
     }
    
     /*
         1. forName()方法抛出ClassNotFoundException
         2. className必须是类名或者接口
     */
    

通过反射获取构造方法并使用

自定义Employee类
package reflect;

import java.time.LocalDate;

public class Employee{
    
    //data field
    private String name;
    private double salary;
    private LocalDate hireDay;
    
    //constructor
    public Employee() {
        System.out.println("c1.getConstructor().newInstance()被执行,调用了无参构造器");        
    }


    public Employee(String name,double salary,int year,int month,int day){
        this.name = name;
        this.salary = salary;
        this.hireDay = LocalDate.of(year,month,day);
        System.out.println("getConstructor(Class,Class....).newInstance(para,para....)被执行");        
    }

    //method
    public String getName(){
        return name;    
    }
    
    public double getSalary(){
        return salary;  
    }
    
    public LocalDate gethireDay(){
        return hireDay;
    }
    
    public void raiseSalary(double byPercent){
        salary += salary * byPercent/100;
    }
    
    public String toString() {
        return "name : " + name + "salary : " + salary + " hireDay : " + hireDay;
    }
}
获取构造方法并使用
  • 获取public构造器

    • Constructor constructors = c1.getConstructors();
  • 获取所有构造器

    • Constructor<Employee>[] constructors = className.getDeclaredConstructors();
  • newIntance()方法的使用

    • 调用无参构造器
      • Constructor<Employee> con = c1.getConstructor();
      • con.newInstance();
    • 调用含参构造器
      • Constructor<Employee> paraCons = c1.getConstructor(String.class,double.class,int.class,int.class,int.class);

      • paraCons.newInstance("调用有参构造器",600,2018,7,18));

          public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
                                throws NoSuchMethodException,
                                       SecurityException
        
      • 返回值为Constructor泛型,参数个数与实际构造器一致,但参数类型为Class

获取构造方法并使用例子程序
public class TestConstructors {
    
    public static void main(String[] args) {
        Class c1 = null;
        
        //获取Class对象
        try {
             c1 = Class.forName("d_1reflect.Employee");
        }catch(ClassNotFoundException e) {
            e.printStackTrace();
        }
        
        //获取构造方法
        System.out.println("========获取所有构造方法========");
        Constructor<Employee>[] constructors = c1.getDeclaredConstructors();        
        
        //输出构造方法        
        for(Constructor cons : constructors) {
            System.out.println(cons);           
        }
        
        System.out.println();
        
        //使用构造方法中的无参构造器
        System.out.println("======使用构造方法中的无参构造器======");
        
        try {
            Constructor<Employee> nonParaCons = c1.getConstructor();
            System.out.println(nonParaCons.newInstance());
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | NoSuchMethodException | SecurityException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        
        System.out.println();
                
        //使用构造方法中的含参构造器
        System.out.println("======使用构造方法中的含参构造器======");
        try {
            Constructor<Employee> paraCons = c1.getConstructor(String.class,double.class,int.class,int.class,int.class);
            System.out.println(paraCons.newInstance("调用有参构造器",600,2018,7,18));
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }       
    }   
}

通过反射获取普通方法并使用

  • 获取所有普通方法

    • Method[] method = c1.getDeclaredMethods();
  • 获取单个普通方法

    • Method m = c1.getDeclaredMethod("getName");

        public Method getDeclaredMethod(String name,Class<?>... parameterTypes)
            throws NoSuchMethodException,SecurityException
      
      • 返回值为Method类型,两个参数,第一个参数为String类,即方法名称,第二个参数为Class类型
  • 使用普通方法

      public Object invoke(Object obj,Object... args)
            throws IllegalAccessException,
                   IllegalArgumentException,
                   InvocationTargetException
    
    • 返回值为Object,一共两个参数:
    • 第一个参数Object是指调用该方法的对象,第二个参数是实参

通过反射获取普通方法并使用例子程序

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestMethod {
    public static void main(String[] args) {
        //获取Class对象
        Class c1 = null;
        
        try {
            c1 = Class.forName("d_1reflect.Employee");
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        
        //获取所有普通方法并输出
        Method[] method = c1.getDeclaredMethods();
        
        System.out.println("===========获取所有普通方法===========");
        for(Method m : method) {
            System.out.println(m);
        }
        
        ///获取单个普通方法
        System.out.println("===========获取单个普通方法===========");
        Method m = null;
        try {
             m = c1.getDeclaredMethod("getName");
            System.out.println(m);
        } catch (NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }   
        
        //使用普通方法
        System.out.println("===========使用普通方法===========");
        Employee emp;
        try {
            emp = (Employee)c1.getDeclaredConstructor(String.class,double.class,int.class,int.class,int.class).newInstance("hahaha",200,2018,7,18);
            System.out.println("调用Method类中invoke(Object,para)方法后 : " + m.invoke(emp, null));
        } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
                | NoSuchMethodException | SecurityException e) {
            e.printStackTrace();
        }   
    }
}

/*
 * 在JDK1.8中输出结果为:
 * -----------------------------------------------------------------------
 * ===========获取所有普通方法===========
    public java.lang.String d_1reflect.Employee.toString()
    public java.lang.String d_1reflect.Employee.getName()
    public void d_1reflect.Employee.setName(java.lang.String)
    public double d_1reflect.Employee.getSalary()
    public java.time.LocalDate d_1reflect.Employee.gethireDay()
    public void d_1reflect.Employee.raiseSalary(double)
    public java.lang.String d_1reflect.Employee.testMethod(java.lang.String)
    ===========获取单个普通方法===========
    public java.lang.String d_1reflect.Employee.getName()
    ===========使用普通方法===========
    调用Method类中invoke(Object,para)方法后 : hahaha
    -----------------------------------------------------------------------
 * */

通过反射获取成员变量

  • 获取所有成员变量信息

    • Field[] fields = c1.getDeclaredFields();
  • 获取public成员变量信息

    • Field[] fields = c1.getFields();
  • 获取单个成员变量信息

    • Field f = c1.getDeclaredField("name");

        public Field getDeclaredField(String name)
             throws NoSuchFieldException,SecurityException
      
    • 返回值为Field,有一个参数,为成员变量名字

  • 使用成员变量

      Employee emp = (Employee)c1.getConstructor().newInstance();
          
      f.setAccessible(true);//暴力反射,解除私有设定
          
      f.set(emp, "xixixi");
    
    
    
      public void set(Object obj,Object value)
              throws IllegalArgumentException,
                  IllegalAccessException
    
    • 无返回值,共两个参数,第一个参数是:要设置的对象,第二个参数是要设置的值
    • 此时注意private的成员变量不可直接访问,但是
    • setAccessible()方法可解除私有设定

通过反射获取成员变量例子程序

public class TestField {
    public static void main(String[] args) {
        
        Class c1 = null;
        //获取Class对象
        try {
            c1 = Class.forName("d_1reflect.Employee");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        //获取成员变量信息
        Field[] fields = c1.getDeclaredFields();
        
        System.out.println("=========获取成员变量信息=========");
        for(Field field : fields) {
            System.out.println(field);
        }
        
        //获取单个成员变量信息
        System.out.println("=========获取单个成员信息=========");
        Field f = null;
        try {
            f = c1.getDeclaredField("name");
            System.out.println(f);
        } catch (NoSuchFieldException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        //使用成员变量
        Employee emp;
        try {
            emp = (Employee)c1.getConstructor().newInstance();
            f.setAccessible(true);//暴力反射,解除私有设定
            f.set(emp, "xixixi");
            System.out.println("使用了set方法修改成员变量 name: " + emp.getName());
        } catch (IllegalArgumentException | IllegalAccessException | InstantiationException | InvocationTargetException
                | NoSuchMethodException | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }       
    }
}
/*
 * 在JDK1.8中输出结果为:
 * ---------------------------------------------------------
 * =========获取成员变量信息=========
    private java.lang.String d_1reflect.Employee.name
    private double d_1reflect.Employee.salary
    private java.time.LocalDate d_1reflect.Employee.hireDay
    =========获取单个成员信息=========
    private java.lang.String d_1reflect.Employee.name
    c1.getConstructor().newInstance()被执行,调用了无参构造器
    使用了set方法修改成员变量 name: xixixi
    ---------------------------------------------------------
 * */

反射与配置文件结合使用

  • 配置文件pro.txt,注意是要放在工程下面

      className = d_1reflect.Employee
      methodName = testMethod
    
  • 主程序:从配置文件中获取ClassName生成Class对象,并调用方法

      public static void main(String[] args) {
      
          Class c1 = null;
          //获取创建的Class对象
          try {
              c1 = Class.forName(getValue("className"));
          } catch (ClassNotFoundException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }
          
          Method m;
          try {
              m = c1.getDeclaredMethod(getValue("methodName"));
              m.invoke((Employee)c1.getConstructor().newInstance());
          } catch (NoSuchMethodException | SecurityException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          } catch (IllegalAccessException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          } catch (IllegalArgumentException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          } catch (InvocationTargetException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          } catch (InstantiationException e) {
              // TODO Auto-generated catch block
              e.printStackTrace();
          }       
      }
    
  • 配置文件的调用与返回

      public static String getValue(String str) {
          Properties pro = new Properties();  //获取配置文件对象
          FileReader in;
          try {
              in = new FileReader("pro.txt");
              pro.load(in);
          } catch (FileNotFoundException e) {
              e.printStackTrace();
          } catch (IOException e) {
              e.printStackTrace();
          }
          return pro.getProperty(str);
      }
    
      /*
       * 在JDK1.8中输出结果为:
       * --------------------------------------------------
       *  c1.getConstructor().newInstance()被执行,调用了无参构造器
          testMeod()方法被执行
          --------------------------------------------------
       * */
    

相关文章

  • 反射知识的理解

    反射 本文参考自:https://blog.csdn.net/sinat_38259539/article/det...

  • 反射的理解

    概念: 创建对象时会先加载类的字节码文件 类的字节码文件是一个模板,必须最早加载到内存中,JVM以此来创建对象 反...

  • Laravel IOC容器深度剖析

    1、基础知识预备 1.1 PHP 反射详解 什么是反射?直观理解就是根据到达地找到出发地和来源。比如,一个光秃秃的...

  • 你需要理解的 Java 反射机制知识总结

    你需要理解的 Java 反射机制知识总结 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法...

  • Java互联网公司-经典面试题附答案

    基础:Java 反射?反射有什么缺点?你是怎么理解反射的(为什么框架需要反射)?优点:反射具有解耦性,缺点:反射属...

  • android 面试相关基础问题

    一:题目 1:java核心思想 2:java高级知识,注解,反射,泛型的理解与作用 3:framework有那方面...

  • 反射机制的理解

    Reflection 是 Java 程序开发语言的重要特征之一,是学习Java必须知识点。 Java反射机制主要提...

  • 你需要理解的Java反射机制知识总结

    反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个...

  • Java反射机制详解(一)

    接下来我们将介绍Java反射机制的一系列的知识。本篇文章主要针对Java反射机制的介绍以及反射API的使用知识。 ...

  • 理解4:反射

    介绍 指在运行状态中:任意一个类,都能够知道这个类所有属性和方法;任意一个对象,都能调用它的任意一个属性和方法; ...

网友评论

      本文标题:反射知识的理解

      本文链接:https://www.haomeiwen.com/subject/tnoapftx.html