反射
反射,在运行时,动态分析或使用一个类进行工作。
反射是一套 API,是一种对底层的对象操作技术
类加载
类加载,生成.class文件,保存类的信息
类对象,是一个描述这个类信息的对象,对虚拟机加载类的时候,就会创建这个类的类对
象并加载该对象。
Class,是类对象的类。称为类类。只有对象才会被加载到虚拟机中。一个类只会被加载
一次。
2、获得类对象的三种方式:(类对象不用 new 的方法得到的)
1)也可以用 类名.Class,获得这个类的类对象。
2)用一类的对象掉用 a.getClass(),得到这个对象的类型的类对象。
3)也可以使用 Class.forName(类名)(Class 类中的静态方法),也可以得到这个类的类对象,
(注意,这里写的类名必须是全限定名(全名),是包名加类名,XXX.XXX.XXXX)。强制类加载,这种方法是经常使用的。
一个类的类对象是唯一的。
在使用 Class.forName(类名)时,如果使用时写的类名的类,还没有被加载,则会加载这个类。
Class c;
c.getName(); 返回类名
c.getSuperclass(); 这个方法是获得这个类的父类的类对象。
c.getInterfaces(); 会获得这个类所实现的接口,这个方法返回是一个类对象的数组。
方法对象是类中的方法的信息的描述。
java.lang.reflect
类 Method
--java.lang.Object
--java.lang.reflect.AccessibleObject
--java.lang.reflect.Method
所有已实现的接口:
AnnotatedElement, GenericDeclaration, Member
java.lang.reflect.Method,方法类的对象可以通过类对象的 getMethods() 方法获得,获得的是一个方法对象的数组,获得类中的定义的所有方法对象,除了构造方法。
构造方法对象,是用来描述构造方法的信息。
java.lang.reflect
类 Constructor<T>
java.lang.Object
--java.lang.reflect.AccessibleObject
--java.lang.reflect.Constructor<T>
类型参数:
T - 在其中声明构造方法的类。
所有已实现的接口:
AnnotatedElement, GenericDeclaration, Member
java.lang.reflect.Constructor 构造方法类的对象可以通过类对象的 getConstructors()方法获得,获得这个类的所有构造方法对象。
属性对象,使用来描述属性的信息。
java.lang.reflect
类 Fieldjava.lang.Object
--java.lang.reflect.AccessibleObject
--java.lang.reflect.FieldField 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
所有已实现的接口:AnnotatedElement, MembergetFields() 返回一个包含某些
Field
对象的数组,这些对象反映此Class
对象所表示的类或接口的所有可访问公共字段。
public class TestClass { public String publicVoid() { return "运行了 publicVoid方法"; } void defaultVoid() { System.out.println("运行了DefaultVoid方法!!!!!"); } private String privateInt(int i) { return "运行了 privateInt方法,参数值:" + i; } static String staticVoidString(String s) { return "运行了staticVoidString方法,参数值:" + s; } public void test(int a) { System.out.println(a + "int parameter method"); } public void test(Integer a) { System.out.println(a + "Integer parameter method"); } public String toString() { return "name"; } }
在反射时,如果我直接调用私有方法,会出现
Exception in thread "main" java.lang.IllegalAccessException: Class ClassTest can not access a member of class TestClass with modifiers "private"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
at java.lang.reflect.Method.invoke(Method.java:588)
at ClassTest.main(ClassTest.java:29)
TestClass class1 = new TestClass(); // 类加载 Class c1 = TestClass.class; Class c2= Class .forName("TestClass"); Class c3 = class1.getClass(); System.out.println(c1); System.out.println(c3); // --1 调用一个类的公开方法并且有返回值但是无参数 Method m1 = c3.getMethod("publicVoid"); // null是因为publicVoid()是个无参的方法,当然也可以填写一个长度为0的数组 Object res1 = m1.invoke(class1, null); System.out.println("方法1的测试结果返回值为:\t" + res1); // --2 调用一个权限为default方法并且返回值为Void但是无参数 // getMethod方法只能访问公开的方法。但是getDeclaredMethod只能访问子类声明的方法,不过可以访问私有方法。 Method m2 = c3.getDeclaredMethod("defaultVoid"); // 访问有权限的方法时,需使用此方法设置访问性,否则会因为权限不够无法访问。 m2.setAccessible(true); // 填写一个长度为0的数组是因为defaultVoid()是个无参的方法,当然也可以填null Object res2 = m2.invoke(class1, new Object[0]); System.out.println("方法2的测试结果返回值为:\t" + res2); // --3 调用一个私有的方法并且有返回值有基本类型int参数 Method m3 = c3.getDeclaredMethod("privateInt", int.class); m3.setAccessible(true); // null是因为publicVoid()是个无参的方法,当然也可以填写一个长度为0的数组 Object res3 = m3.invoke(class1, new Integer(3)); System.out.println("方法3的测试结果返回值为:\t" + res3); // --4 调用一个静态的方法并且有返回值有String类型的参数 Method m4 = c3.getDeclaredMethod("staticVoidString", String.class); m4.setAccessible(true); Object res4 = m4.invoke(class1, "测试4"); System.out.println("方法4的测试结果返回值为:\t" + res4); Method m5 = c3.getDeclaredMethod("test", int.class); Method m6 = c3.getDeclaredMethod("test", Integer.class); System.out.println(int.class); System.out.println(Integer.class); Integer in = Integer.valueOf(3); m5.invoke(class1, 1); m6.invoke(class1, in); m5.invoke(class1, 1); m6.invoke(class1, in); class1.test(1); class1.test(in);
int 和Integer对象是可以自动转换的,但是在反射情况下,作为参数时二者是不同的类型的。
在test(int i)和test(Integer in)同时存在的情况下,如果调用的是方法中是Integer对象,则不进行自动拆包转换,而是直接调用test(Integer in)方法