本文部分内容参考 博客 。点击链接可以查看原文。
反射是指在运行时将类的属性、构造函数和方法等元素动态地映射成一个个对象。通过这些对象我们可以动态地生成对象实例,调用类的方法和更改类的属性值。
什么情况下运用JAVA反射呢?如果编译时根本无法预知对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,此时就必须使用反射。
使用反射可以实现下面的功能:
前面已经介绍过了,每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类。在Java程序中获得Class对象通常有如下3种方式。
对于第一种方式和第二种方式都是直接根据类来取得该类的Class对象,相比之下,第二种方式有如下两种优势。
也就是说,大部分时候我们都应该使用第二种方式来获取指定类的Class对象。但如果我们只有一个字符串,例如“java.lang.String”,若需要获取该字符串对应的Class对象,则只能使用第一种方式,使用Class的forName(String clazzName)方法获取Class对象时,该方法可能抛出一个ClassNotFoundException异常。一旦获得了某个类所对应的Class对象之后,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了。
通过class类我们能够获取大量的信息:
上面的多个getMethod()方法和getConstructor()方法中,都需要传入多个类型为Class<?>的参数,用于获取指定的方法或指定的构造器。关于这个参数的作用,假设某个类内包含如下3个info方法签名:
这3个同名方法属于重载,它们的方法名相同,但参数列表不同。在Java语言中要确定一个方法光有方法名是不行的,例如,我们指定info方法——实际上可以是上面3个方法中的任意一个!如果需要确定一个方法,则应该由方法名和形参列表来确定,但形参名没有任何实际意义,所以只能由形参类型来确定。例如,我们想要确定第二个info方法,则必须指定方法名为info,形参列表为String.class——因此在程序中获取该方法使用如下代码:
clazz.getMethod("info",String.class);
Constructor c = clazz.getConstructor(String.class); c.newInstance("xx");
Method setProName = aClass.getDeclaredMethod("setProName",String.class); setProName.setAccessible(true); etProName.invoke(product,"我是一个产品");
Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("fieldName:"+declaredField.getName()+" filedType:"+declaredField.getType()); } Field proName = aClass.getDeclaredField("proName"); proName.setAccessible(true); proName.set(product,"我是一个产品"); System.out.println("修稿属性:"+product);
//使用反射动态地创建数组 //创建一个元素类型为String,长度为3的数组 Object arr = Array.newInstance(String.class, 3); //依次为arr数组中index为0,1,2的元素赋值 Array.set(arr, 0, "荣耀盒子"); Array.set(arr, 1, "荣耀8手机"); Array.set(arr, 2, "华为mate9保时捷版"); Object o1= Array.get(arr, 0); Object o2= Array.get(arr, 1); Object o3= Array.get(arr, 2); System.out.println(o1); System.out.println(o2); System.out.println(o3);
public class ReflectDemo { public static void main(String[] args) throws Exception { Class<Product> aClass = Product.class; Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors(); for (Constructor<?> declaredConstructor : declaredConstructors) { System.out.println(declaredConstructor.getName()); } Constructor<Product> constructor = aClass.getConstructor(int.class, String.class); Product product = constructor.newInstance(10, "ds"); System.out.println("创建对象:"+product); //获取方法并调用 Method setProName = aClass.getDeclaredMethod("setProName", String.class); setProName.setAccessible(true); setProName.invoke(product,"我是一个产品"); System.out.println("调用方法:"+product); //获取属性,并设置属性的值 Field[] declaredFields = aClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println("fieldName:"+declaredField.getName()+" filedType:"+declaredField.getType()); } Field proName = aClass.getDeclaredField("proName"); proName.setAccessible(true); proName.set(product,"我是一个产品"); System.out.println("修稿属性:"+product); //使用反射动态地创建数组 //创建一个元素类型为String,长度为3的数组 Object arr = Array.newInstance(String.class, 3); //依次为arr数组中index为0,1,2的元素赋值 Array.set(arr, 0, "荣耀盒子"); Array.set(arr, 1, "荣耀8手机"); Array.set(arr, 2, "华为mate9保时捷版"); Object o1= Array.get(arr, 0); Object o2= Array.get(arr, 1); Object o3= Array.get(arr, 2); System.out.println(o1); System.out.println(o2); System.out.println(o3); System.out.println("end..."); } }