Java中的反射机制
java的反射机制是java的特性之一,反射机制是构建框架技术的基础所在,使用反射可以使程序更加灵活,避免将程序写死在代码里。相对于很多初学者只接触过java基础的人,反射还是一个很朦胧难懂的概念,下面我们就来说一下反射的一些应用。
java反射机制是指在运行状态中,动态获取信息以及动态调用对象方法的功能。java反射有3个动态性质:1.运行时生成对象实例,2.运行期间调用发放,3.运行时更改属性。
那么反射的原理是什么呢?那我们就要先来看一下java程序的执行过程,想要java程序能够运行,java类必须被java虚拟机加载。运行程序都是在编译时就已经加载了所需要的类。在这里就不得不提一下了,相信很多人对于什么是编译时,什么是运行时还没有一个明确的概念,编译时就是编译器帮你把代码翻译成设备可以识别的代码,也就是说编译器在编译时会做一些简单的工作,比如检查你的语法有没有错误,关键字或者名称书写有无错误,加载类,这都是编译时要做的事情,那运行时都做了什么呢?运行时就是当你的程序开始,代码被装载到内存中后就是运行时,运行时检查就是在你的内存中做操作与判断,下面我们来举个小例子:
int[] nums = new int[3];nums[4] = 12;
很显然,上面这段代码会出现数组下标越界的错误,可是程序在编译时并没有报错,而是在运行时才会报出一个ArrayIndexOutOfBoundsException的错误,这就是编译时和运行时的区别。
而java的反射机制在编译时并不确定是哪个类被加载了,他是在程序运行时候才加载和使用,我们用一张简单的图来看一下反射的执行过程:
Java反射机制能够知道类的基本结构,这种对于java类结构探知的能力成为“自审”,像我们使用eclipse一类软件书写代码时的自动提示功能就是用的java反射的原理。那么通过java的反射,我们可以实现什么功能呢?1.在运行时判断任意一个对象所属类,2.在运行时构造任意一个类的对象,3.在运行时判断任意一个类所具有的属性和方法,4.在运行时调用任意一个对象的方法。java反射常用的类有Class类:反射的核心类,通过Class类可以获取类的属性,方法等内容。Filed类:表示类的属性,可以获取和设置类中属性的值。Method类:表示类的方法,他可以用来获取类中方法的信息,或者执行方法。Constructor类:表示类的构造方法。
好了,我们已经了解了java反射的一些基本信息,下面我们就逐一用代码的方式实现反射的各个功能:
第一个,也是最简单的一个,首先要使用、Class类肯定要先实例化出他,可是Class类没有构造方法,那我们要怎样实例化呢,下面有三种创建Class类的方法:
public static void main(String[] args) { //第一种方法,通过对象.getClass()方法 User user = new User();Class<? extends User> cs = user.getClass();System.out.println(cs); //第二种方法,通过类名.class Class<User> cs1 = User.class;System.out.println(cs1); //第三种方法,通过Class本身的forName()方法,注意forName()方法会抛出一样,并且里面的参数需要完整的包名和类名 Class<?> cs2 = null; try { cs2 = Class.forName('cn.fanfu.demo.User');} catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace();}System.out.println(cs2); }
其中第三种forName()方法可以在类不确定的情况下实例化Class,更具灵活性。
第二个是通过Class类的有参构造创建Class类对象的新实例:
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { //在这里为了更直观的展示,直接使用String类 Class<?> cs =Class.forName('java.lang.String'); char[] ch = {’大’,’家’,’好’,’!’,’!’}; //调用Class类的有参构造函数,函数里的值为类.class Constructor<?> cst = cs.getConstructor(char[].class); String name = (String) cst.newInstance(ch); System.out.println(name); //因为这里的异常会使代码没有直观的显示,所以我直接抛给虚拟机 }
第三个是取得类的构造、接口、方法、属性等一系列元素:
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException { //先创建好两个对象 Class<?> cs = Class.forName('cn.fanfu.demo.User');Constructor<?>[] con = null; //通过getConstructors()方法返回一个Constructor[]数组,数组里存储的是该类的各个构造 con = cs.getConstructors(); for (Constructor<?> item : con) { System.out.println(item);} //通过getInterfaces()方法返回一个Class<?>[]数组,数组里存储的是该类的各个接口 Class<?>[] inter = cs.getInterfaces(); for (Class<?> item : inter) { System.out.println(item);} //通过getSuperclass()方法返回一个Class<?> Class<?> parent = cs.getSuperclass(); //java中只支持单继承,所以只有一个父类 System.out.println(parent); //通过getMethods()方法返回一个Method[]数组,数组里存储的是该类的各个方法 Method[] method = cs.getMethods(); for (Method item : method) { System.out.println(item);} //通过getDeclaredFields()方法返回一个Field[]数组,数组里存储的是该类的各个属性 Field[] fiel = cs.getDeclaredFields(); for (Field item : fiel) { System.out.println(item);} //getDeclaredFields()方法可以获取全部属性,getFields()方法只能获取到公有属性 Field[] fiel1 = cs.getFields(); for (Field item : fiel1) { System.out.println(item);} }
第四个是获取或修改类的属性的值:
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException { //创建User对象 User us = new User();us.setAge(12);us.setName('张三');Class<?> cs = us.getClass(); //获取私有属性的值 Field fl = cs.getDeclaredField('name'); //要先设置允许访问 fl.setAccessible(true); //通过get方法指定对象获取值 String name = (String) fl.get(us);System.out.println(name); //通过set方法指定对象并修改值 fl.set(us, '李四');String name2 = (String) fl.get(us);System.out.println(name2); }
第五个是通过反射调用方法:
public static void main(String[] args) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchFieldException { //创建User对象 User us = new User();us.setAge(12);us.setName('张三');Class<?> cs = us.getClass(); //通过getMethod()方法获取类中方法,该方法有两个参数,一个指定方法名,一个指定方法中参数的类型 Method mm = cs.getMethod('say'); //通过invoke()方法调用方法,该方法有两个参数,一个指定对象,另一个传递参数 mm.invoke(us); }
好了,关于反射的介绍就先这么多了,其他的还有一些列如操作数组集合,都是一些变通用法,就不多做介绍。
相关文章: