反射是框架设计的灵魂(使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)
一、反射的概述 Java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
要想解剖一个类,必须先要获取到该类的字节码文件对象。而解剖使用的就是Class类 中的方法。所以先要获取到每一个字节码文件对应的Class类型的对象。
反射就是把java类中的各种成分映射成一个个的Java对象。例如:一个类有:成员变量、方法、构造方法、包等等信息,利用反射技术可以对一个类进行解剖,把一个个组成部分映射成一个个对象。
(其实:一个类中这些成员方法、构造方法、在加入类中都有一个类来描述)。
以上的总结就是什么是反射
如图是类的正常加载过程:反射的原理在与class对象。
熟悉一下加载的时候:Class对象的由来是将class文件读入内存,并为之创建一个Class对象。
二、获取字节码对象的三种方式。 1 2 3 4 5 6 7 8 9 10 Class class1 = Class.forName("cn.coder.Person" ); Class class2 = Person.class; Person person = new Preson(); Class class3 = person.getClass();
有了字节码文件对象才能获得类中所有的信息,我们在使用反射获取信息时,也要考虑使用上面哪种方式获取字节码对象合理,视不同情况而定。
三、优雅的利用字节码对象 下面通过一个实例介绍Class类的功能
3.1通过字节码对象获取构造器实例对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 Class class1 = Class.forName("cn.coder.Person" ); Person p1 = (Person)class1.newInstance(); Class class2 = Class.forName("cn.coder.Person" ); Construnctor con = class2.getConstructor(int .class, String.class); Construnctor con0 = class2.getConstructor(new Class[] {int .class, String.class}); Person p2 = (Person)con.newInstance(18 ,"臭弟弟" ); Person p0 = (Person)con0.newInstance(new Object[]{18 , "臭弟弟" }); Constructor[] con = class2.getConstructors(); for (int i=0 ; i<con.length; i++){ Class[] parameterTypes = con[i].getParameterTypes(); for (int j=0 ; j<paraparameterTypes.length; j++){ System.out.print(paraparameterTypes[j].getName() + "," ); } }
3.2获取成员变量并使用—Filed对象 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 Class personClass = Person.class; Field[] fields = personClass.getFields(); Field[] fields1 =personClass.getDeclaredFields(); System.out.println("---------------" ); Field a = personClass.getField("a" ); Person p = new Person(); Object value = a.get(p); a.set(p, "111" ); System.out.println("---------------" ); Field d = personClass.getDeclaredField("d" ); d.setAccessible(true );
3.3获得方法并使用 Method 和上面类似 Fileld相似的
可以通过Class.getMethod(String, Class…) 和 Class.getDeclaredMethod(String, Class…)方法可以获取类中的指定方法或者所有方法,获取后可进行遍历。如果为私有方法,则需要打开一个权限。setAccessible(true); 用invoke(Object, Object…)可以调用该方法,跟上面同理,也能一次性获得所有的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 Class p2 = Class.forName("com.demo.Reflect.Person" ); Person person = (Person) p2.newInstance(); Method[] method2 = p2.getDeclaredMethods(); for (Method method : method2) { method.setAccessible(true ); System.out.println(method.getName()); Class<?>[] parameterTypes = method.getParameterTypes(); for (int i = 0 ; i < parameterTypes.length; i++) { System.out.print(parameterTypes[i].getName() + "," ); } method.invoke(person, 3 ); }
3.4获得该类的所有接口 Class[] getInterfaces():确定此字节码对象所表示的类或接口实现的接口
返回值:接口的字节码文件对象的数组
3.5获取指定资源的输入流 InputStream getResourceAsStream(String name)
return:一个 InputStream 对象;如果找不到带有该名称的资源,则返回 null
参数:所需资源的名称,如果以”/“开始,则绝对资源名为”/“后面的一部分。
四、一个整体的实例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 package me.zhangsanfeng;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;public class Reflection { public Object copy (Object object) throws Exception { Class<?> classType = object.getClass(); Constructor<?> cons = classType.getConstructor(new Class[]{}); Object retObject = cons.newInstance(new Object[]{}); Field[] fields = classType.getDeclaredFields(); for (Field field:fields){ String nameOfField = field.getName(); String fristWord = nameOfField.substring(0 , 1 ).toUpperCase(); String getMethodName = "get" +fristWord+nameOfField.substring(1 ); String setMethodName = "set" +fristWord+nameOfField.substring(1 ); Method getMethod = classType.getMethod(getMethodName, new Class[]{}); Method setMethod = classType.getMethod(setMethodName, new Class[]{field.getType()}); Object value = getMethod.invoke(object, new Object[]{}); setMethod.invoke(retObject, new Object[]{value}); } return retObject; } public static void main (String[] args) throws Exception { Class<?> classType = Person.class; Constructor cons = classType.getConstructor(new Class[]{String.class,int .class,double .class}); Object perOfLee = cons.newInstance(new Object[]{"Lee" ,25 ,8000 }); Class <?> classOfReflect = Class.forName("me.zhangsanfeng.Reflection" ); Object reflect = classOfReflect.newInstance(); Method methodOfCopy = classOfReflect.getMethod("copy" , new Class[]{Object.class}); Object finalObject = methodOfCopy.invoke(reflect, perOfLee); Person copyPerson = (Person)finalObject; System.out.println(copyPerson.getName()+", " +copyPerson.getAge()+", " +copyPerson.getSalary()); } } class Person { private String name; private int age; private double salary; public Person () { } public Person (String name, int age, double salary) { this .name = name; this .age = age; this .salary = salary; } public String getName () { return name; } public void setName (String name) { this .name = name; } public int getAge () { return age; } public void setAge (int age) { this .age = age; } public double getSalary () { return salary; } public void setSalary (double salary) { this .salary = salary; } }