黑马程序员技术交流社区

标题: 关于反射 虽然传闻说点招不考反射 但是还要学习一下 [打印本页]

作者: 山水云梦    时间: 2016-7-4 22:43
标题: 关于反射 虽然传闻说点招不考反射 但是还要学习一下
1、反射-概述(掌握)

反射就是在程序运行过程中,通过.class文件动态的获取类的信息(属性,构造,方法),并调用


注意:JAVA不是动态语言,因为动态语言强调在程序运行过程中不仅能获取并调用类里面的属性和方法,还要求能够给类增加属性和方法,而JAVA中的反射只能获取调用,不能修改类的结构


在反射中包含Declared的方法表示获取私有的成员内容,一般结合setAccessible(true)方法一起使用


2、创建Class文件的三种方式(掌握)

          Class.forName("类全名");
          对象名.getClass();
          类名.class


          推荐使用:Class.forName("类全名");
3、获取构造方法并创建对象(掌握)

概述:
     java.lang.reflect.Constructor:构造方法管理器,通过该对象的newInstance方法能有创建构造方法
一、步骤
1、获取Class对象
2、通过调用getDeclaredConstructor或者getConstructor 方法创建构造器(Constructor)对象,如果构造方法没有形式参数写null
     public Constructor getDeclaredConstructor(形式参数1对应的.class对象, 形式参数2对应的.class对象....):该方法可以获取私有构造方法
     public Constructor getConstructor(形式参数1对应的.class对象, 形式参数2对应的.class对象....):该方法不能获取私有构造方法
3、如果获取到的是私有的构造方法的构造器对象,需要调用构造器对象的setAccessible(true)方法
4、通过构造器对象的newInstance(实际参数1, 实际参数2)创建对象,如果没有实际参数写null


二、举例
     1、通过private Person(String name, int age)创建对象
          Class clazz =  Class.forName("com.itcast.Person");//必须通过类全名获取
          Constructor con = clazz.getDeclaredConstructor(String.class, int.class);//形式参数列表对应的.class列表
con.setAccessible(true);//此处不设置,无法创建该对象,因为构造方法是私有的
          Object obj = con.newInstance("zhangsan",120);//调用newInstance(实际参数列表)创建对象


     2、通过public Person()创建对象
          Class clazz =  Class.forName("com.itcast.Person");//必须通过类全名获取
          Constructor con = clazz.getDeclaredConstructor(null);//因为没有形式参数,所以写null
          con.setAccessible(true);//此处不设置,无法创建该对象,因为构造方法是私有的
          Object obj = con.newInstance();//因为不需要实际参数,所以调用无参的newInstance方法



4、获取属性并调用(掌握)

概述:
     java.lang.reflect.Field:属性管理器对象,可以对该类的对象的属性值进行修改和获取


一、步骤
     1、获取Class对象
     2、通过调用getDeclaredField("属性名")或通过调用getField("属性名") 获取属性管理器
     3、如果获取的是私有的属性,调用属性管理器的setAccessible(true)方法
     4、调用属性管理器的set(该类的对象,值) 来设置属性值
          调用属性管理器的get(该类的对象)来获取属性值


二、举例
          Person p1 = new Person();
          Person p2= new Person();
          Class clazz =  Class.forName("Person");//第一步获取Class对象
          Field field = clazz.getDeclaredField("name");//第二步通过调用getDeclaredField("属性名")或通过调用getField("属性名") 获取属性管理器
          field.setAccessible(true);//第三步如果获取的是私有的属性,调用属性管理器的setAccessible(true)方法
          field.set(p1, "张三");//第四步用属性管理器的set(该类的对象,值) 来设置属性值
          field.set(p2, "李四");

          System.out.println(field.get(p1));//第四步调用属性管理器的get(该类的对象)来获取属性值
          System.out.println(field.get(p2));
     


5、获取成员方法并调用(掌握)

概述:
      java.lang.reflect.Method:方法管理器,可以执行该类的对象的方法


一、步骤
     1、获取Class对象
     2、通过调用getDeclaredMethod("方法名",形式参数1.class, 形式参数2.class..)或通过调用geMethod("方法名",形式参数1.class, 形式参数2.class..) 获取属性管理器,如果没有形式参数写null
     3、如果获取的是私有的方法,调用方法管理器的setAccessible(true)方法
     4、通过属性管理器的invoke(该类的对象,实际参数)来执行方法,如果没有实际参数写null


二、案例
          Person p1 = new Person("张三",13);
          Person p2= new Person("李四",14);
          Class clazz =  Class.forName("Person");

          /*
          * 调用setName方法
          */
          Method setName = clazz.getDeclaredMethod("setName", String.class);
          setName.setAccessible(true);//如果getName方法是私有的,此处必须写
          setName.invoke(p1, "张三改");

          /*
          * 调用getName方法
          */
          Method getName = clazz.getDeclaredMethod("getName", null); //获取Person类的getName方法对应的方法管理器
          getName.setAccessible(true);//如果getName方法是私有的,此处必须写
          Object object = getName.invoke(p1, null);//执行p1对象的getName方法,并且将返回值赋值给object
          System.out.println(object);

6、反射练习(掌握)

1:通过反射修改成员变量的值,包括私有
2: 通过反射运行配置文件
   在JAVA项目下新建配置文件config,内容为
     class=Person
         name=jack


   JAVA代码:
          Properties p = new Properties();
          p.load(new FileReader("config"));
          String className  = (String)p.get("class");
          String name = (String)p.get("name");

          Class clazz = Class.forName(className);
          //创建对象
          Constructor constructor = clazz.getConstructor(null);
          Object instance = constructor.newInstance();

          //通过setName设置name属性
          Method setName = clazz.getDeclaredMethod("setName", String.class);
          setName.invoke(instance,name );

          //通过getName设置name属性
          Method method = clazz.getDeclaredMethod("getName",null);
          Object object = method.invoke(instance, null);
          System.out.println(object);


3: 通过反射给 ArrayList<Integer>中添加String 类型的数据
          ArrayList<Integer> list = new ArrayList<Integer>();
          list.add(123);


        Class clazz =  Class.forName("java.util.ArrayList");//必须通过类全名获取
        Method method = clazz.getDeclaredMethod("add", Object.class);
        method.setAccessible(true);
        method.invoke(list, "ss");

        for(Object obj: list){
             System.out.println(obj);
        }





欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2