黑马程序员——反射

来源:互联网 发布:linux vi使用 编辑:程序博客网 时间:2024/05/17 07:00
 ------- android培训、java培训、期待与您交流! ----------


反射

反射,在运行时,动态分析或使用一个类进行工作。
反射是一套 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
类 Field

java.lang.Object
--java.lang.reflect.AccessibleObject
   --java.lang.reflect.Field

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类(静态)字段或实例字段。
所有已实现的接口:AnnotatedElement, Member

getFields() 返回一个包含某些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)方法

原创粉丝点击