Java---反射机制
Posted H小白
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的核心类库。Extclassloader与APPclassloader都是classloader的子类。extclassLoader负责装载JRE扩展目录ext中的jar类包,而APPClassloader则负责装载classPath路径下的类包。根装载器是extclassloader的父装载器,而extclassloader是APPclassloader的父装载器。在默认情况下,使用APPclassloader装载应用程序。
重要方法
Class loadClass(String 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可以将实现类、参数信息等配置在其对应的配置文件中,那么当需要更改实现类或参数信息时,只需要修改配置文件即可,我们还可以对某对象所需要的其它对象进行注入,这种注入都是在配置文件中做的。
Spring的IOC的实现原理利用的就是Java的反射机制,Spring的工厂类会帮我们完成配置文件的读取、利用反射机制注入对象等工作,我们可以通过bean的名称获取对应的对象。
以上是关于Java---反射机制的主要内容,如果未能解决你的问题,请参考以下文章