Java---反射机制

概念

  • Reflection也就是反射 是Java被视为动态(或准动态)语言的一个关键性质
  • 反射机制指的是程序在运行时能够获取任何类的内部所有信息

反射机制实现功能概述

  • 只要给定类的全名,即可通过反射获取类的所有信息。
  • 反射可以在程序运行时获取任意一个对象所属的类对象。
  • 在运行时可以获取到类中所有属性对象,并对其操作(包括私有属性)。
  • 在运行时可以获取到类中、父类中所有方法,并调用。
  • 目前主流的应用框架如Struts2、Hibernate、Spring、SpringMVC等框架的核心全部是利用Java的反射机制来实现的。

Class反射对象描述类语义结构,可以从Class对象中获取构造函数,成员变量,方法等类元素的反射对象,并以编程的方式通过这些反射对象对目标类对象进行操作。这些反射对象类在java.reflect包中定义,下面是最主要的三个反射类

  • Constructor
  • Method

      1.Class getReturnType()

   2.Class[] getParameterTypes()

   3.Class[] getExceptionTypes()

   4.Annotation[][] getParameterAnnotations()

  • Field

Class对象的机制与实现

反射机制中class对象的常用方法介绍

方法名 释义
getName() 获得类中完整名称
getDeclaredFields() 获得类中的所有属性
getDeclaredMethods() 获得类中所有的方法
getConstructors() 获得类构造方法
newInstance() 实例化类对象(无参构造函数)

 

 

获取class对象的三种方式

//第一种方式
try {
  demo1 = Class.forName("com.jikexueyuan.bean.Book");
} catch (Exception e) {
  e.printStackTrace();
}
System.out.println(demo1);
        
Book bo = new Book();
Object ob = bo;
System.out.println("第二种:"+ob.getClass());
        
demo3 = Book.class;
System.out.println("第三种:"+demo3);
try {
  Book bo1 = (Book)demo3.newInstance();
  System.out.println("实例化后的类对象:"+bo1);
} catch (InstantiationException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
} catch (IllegalAccessException e) {
  // TODO Auto-generated catch block
  e.printStackTrace();
}

Field对象的机制与实现

Java.lang.reflect.Field类,可以操作类/接口中全部属性和属性的信息

Field对象常用方法

方法名 释义
getName() 获得属性名称
getType() 获得属性类型
get(Object obj) 取得obj对象中这个属性的值
set(Object obj, Object value) 向obj对象中这个属性赋值value
setAccessible(true) 启用/禁用访问控制权限(需要操作类中私有属性时使用)

Field对象的操作

//该方法用于使用传递过来的Class对象获取类中的属性
public void show(Class cl){
  Field[] fi = cl.getDeclaredFields();//可以讲私有属性获取到
  for(Field ff : fi){
    System.out.println(ff.getName());
    System.out.println(ff.getType());
  }
  System.out.println("~~~~~~~~~~~~~~~~~~~");

  Field[] fi1 = cl.getFields();//只可以获取到公有属性
  for(Field ff : fi1){
    System.out.println(ff.getName());
    System.out.println(ff.getType());
  }
}
//该方法用于使用传递过来的实体类对象 获取属性 以及属性的值 public void show(Object ob){   Class cl = ob.getClass();   Field[] fi = cl.getDeclaredFields();   try {     for(Field ff : fi){       ff.setAccessible(true);//设置启用       System.out.println(ff.getName()+"值"+ff.get(ob));     }   } catch (Exception e) {     e.printStackTrace();   } }

Method对象的机制与实现

java.lang.reflect.Method类,可以操作类中全部方法

Method对象常用方法

方法名 释义
getName() 获得方法名称
getReturnType() 获得方法返回值类型
invoke(Object obj, Object... args) 利用obj对象调用该方法
getParameterTypes() 获得方法所有参数类型,按照顺序返回Class数组
getDeclaredAnnotations() 获取方法的全部注解

Method对象操作

//该方法用于获取对象的所有方法名称、返回值类型、以及参数信息
public void show(Object ob){
  Class cl = ob.getClass();
  Method[] me = cl.getDeclaredMethods();
  for(Method mm : me){
    System.out.println("方法名称:"+mm.getName());
    System.out.println("方法修饰符:" + Modifier.toString(mm.getModifiers()    ));
    System.out.println("方法返回值类型:"+mm.getReturnType());
    Class[] preType = mm.getParameterTypes();
    System.out.println("方法参数列表:");
    for(Class cll : preType){
      System.out.println(cll.getName());
    }
  }
}
//该方法用于使用传递过来的实体对象 获取其中指定的方法 并调用
public void showUse(Object ob){
  Class cl = ob.getClass();
  try {
    Method me = cl.getMethod("getName", null);
    me.invoke(ob, new Object[0]);
    //方法只有一个参数     Method me1
= cl.getMethod("setName", String.class);     me1.invoke(ob, "西游记");
    //方法有两个及以上参数     Class[] cll
= {String.class,int.class};     Method me2 = cl.getMethod("test", cll);     Object[] obb = {"哈哈",12};     me2.invoke(ob, obb);   } catch (Exception e) {     e.printStackTrace();   } }

示例讲解

编写一个简单示例开始探访Java反射机制的征程,通过比较传统方法以及反射机制创建类实例的不同,来介绍Java反射机制的原理:

  • Car:拥有两个构造函数,一个方法以及三个属性
public class Car {
    private String brand;

    private String color;

    private int maxSpeed;

    //1.默认构造函数
    public Car(){}
    
    //2.带参构造函数
    public Car(String brand,String color,int maxSpeed){
        this.brand = brand;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }
    
    //3.输出文字
    public void introduce() {
       System.out.println("brand:"+brand+";color:"+color+";maxSpeed:"+maxSpeed);
    }

    public String getBrand() {
        return brand;
    }

    public void setBrand(String brand) {
        this.brand = brand;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public int getMaxSpeed() {
        return maxSpeed;
    }

    public void setMaxSpeed(int maxSpeed) {
        this.maxSpeed = maxSpeed;
    }
}
  • 传统调用方法,使用构造函数设置属性或者set方法设置属性

    1. 构造函数方法:Car car = new Car(“红旗轿车”, “黑色”, 180);

    2. Set方法:Car car = new Car(); car.setBrand(“红旗轿车”);

  • Java反射机制,以一种更加通用的方式间接地操作目标类

ReflectTest类

public class ReflectTest {
    
    public static Car  initByDefaultConst() throws Throwable {
        //1.通过类装载器获取程序运行时Car类对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();        
        Class clazz = loader.loadClass("com.jike.spring.chapter03.reflect.Car");
    
        //2.获取类的默认构造器对象并实例化Car
        Constructor cons = clazz.getDeclaredConstructor((Class[])null);
        Car car = (Car)cons.newInstance();
        
        //3.通过反射方法设置属性
        Method setBrand = clazz.getMethod("setBrand",String.class);        
        setBrand.invoke(car,"奔驰");        
        Method setColor = clazz.getMethod("setColor",String.class);
        setColor.invoke(car,"黑色");        
        Method setMaxSpeed = clazz.getMethod("setMaxSpeed",int.class);
        setMaxSpeed.invoke(car,200);        
        return car;
    }
    
    public static Car initByParamConst()  throws Throwable{
        //1.通过类装载器获取Car类对象
        ClassLoader loader = Thread.currentThread().getContextClassLoader();
        Class clazz = loader.loadClass("com.jike.spring.chapter03.reflect.Car");
        
        //2.获取类的带有参数的构造器对象
        Constructor cons = clazz.getDeclaredConstructor(new Class[]{String.class,String.class,int.class});
        
        //3.使参数的构造器对象实例化Car
        Car car = (Car)cons.newInstance(new Object[]{"宝马","红色",180});
        return car;    
    }
    
    public static void main(String[] args) throws Throwable {
        Car car1 = initByDefaultConst();
        Car car2 = initByParamConst();
        car1.introduce();
        car2.introduce();
    }
}

以上便是利用java反射机制来获取class类以及方法。

ClassLoade

类装载器就是寻找类的字节码文件并构造出类在JVM内部表示的对象组件,主要工作由ClassLoader及其子类负责,ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入Class字节码文件。

工作机制

java中把一个类装载到java虚拟机中需要经过以下步骤

  • 装载:查找和导入Class文件

链接:执行校验,准备和解析步骤。校验主要是检查载入class文件数据的正确性;准备主要是给类的静态变量分配存储空间;解析主要是将符号引用转换成直接引用

  • 初始化:对类的静态变量、静态代码块执行初始化工作。类装载器工作主要是由classLoader及其子类来负责的。Classloader又是一个重要的java运行时系统组件,负责在运行时查找和装入class字节码文件。

    Jvm在运行时会产生三个classloader:根装载器、扩展类装载器(EXTClassloader)、系统类装载器(APPClassloader),其中根装载器不是classloader的子类,由于是使用c++来编写的,所以在java中看不到。根装载器来负责加载JRE的核心类库。ExtclassloaderAPPclassloader都是classloader的子类。extclassLoader负责装载JRE扩展目录ext中的jar类包,而APPClassloader则负责装载classPath路径下的类包。根装载器是extclassloader的父装载器,而extclassloaderAPPclassloader的父装载器。在默认情况下,使用APPclassloader装载应用程序。

重要方法

Class loadClassString name

Name:指定类装载器需要装载类的名字,必须要使用全限定名。在初始化类之前,应考虑进行类解析。但并不是所有的类都需要解析,如果java虚拟机只需要知道该类是否存在,或找出该类的超类,则不需要解析

Class defineClass(String name, byte[]b, int off,int len)

将类文件的字节数组来转换成java虚拟机内部的java.lang.class对象。字节数组可从本地文件系统,或者是远程网络获取;name为完全限定名

Class findSystemClass(String name)

从本地文件系统载入class文件,若本地没有该class文件,则会抛出异常,这个方法是java虚拟机默认使用的装载机制

Class findLoadedClass(String name)

调用该方法来查看classloader是否已装入到某个类当中,如果已经装入,则返回java.lang.class对象,否则返回null值,如果强行装载已经存在的类,则会抛出链接错误。

ClassLoader getParent()

获取类装载器的父装载器,除根装载器外,所有的类装载器都有且仅有一个父装载器。可以编写自己的第三方装载器,以实现特殊的需求。类文件被装载并解析之后,在java虚拟机内相应拥有一个对应的java.lang.class类型属性。该类的对象实例则拥有指向这个类描述对象的引用,而类描述对象又拥有指向关联classloader类。每一个类在java虚拟机中都拥有一个对应的java.lang.class对象,它提供了对结构信息的描述。数组、枚举、注解以及基本的java类型。

与IOC关系

Spring中,通过IOC可以将实现类、参数信息等配置在其对应的配置文件中,那么当需要更改实现类或参数信息时,只需要修改配置文件即可,我们还可以对某对象所需要的其它对象进行注入,这种注入都是在配置文件中做的。

SpringIOC的实现原理利用的就是Java的反射机制,Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象。

原文地址:https://www.cnblogs.com/xiaobaizhiqian/p/7755293.html