黑马程序员技术交流社区

标题: 【南京校区】反射的妙用(二) [打印本页]

作者: 大蓝鲸Java    时间: 2018-6-22 12:24
标题: 【南京校区】反射的妙用(二)
【南京校区】反射的妙用(二)

    上一问说了反射,利用反射获取字节码文件对象,利用反射设置对象中变量的值。

   那么文本继续利用反射运行方法,以及面试加分项



(一) 利用反射运行一个非public修饰的方法

   
[AppleScript] 纯文本查看 复制代码
利用反射运行一个私有的方法                                                                        |        对比 public 修饰的方法

        // 获取字节码对象                                                                            |
        Class clazz = Class.forName("com.heima.Student");                |                Class clazz = Class.forName("com.itheima_01.Student");
        // 创建学生对象                                                                                        |
        Object stu = clazz.newInstance();                                                |                Object stu = clazz.newInstance();
        // 暴力反射获取方法                                                                                |
        Method method = clazz.getDeclaredMethod("method");                |                Method m = clazz.getMethod("method");
        // 让jvm不检查权限                                                                                |
        method.setAccessible(true);                                                                |
        // 执行方法                                                                                                |
        method.invoke(stu);                                                                                |                m.invoke(stu);




(二)面试加分项
让字符串可变
                String s = "abc";
                Class clazz = s.getClass();
                Field field = clazz.getDeclaredField("value");
                field.setAccessible(true);
                char[] chs = (char[]) field.get(s);
                chs[0] = 'Q';
                System.out.println(s);


//----------------------------------------------------

                String s = "abc";
                Class clazz = s.getClass();//因为已经有对象存在了,所以用getClass就可以获取到了
                Field field = clazz.getDeclaredField("value");//可以看到,但是得不到这个对象
                field.setAccessible(true);
                //Object object = field.get(s);
                //System.out.println(object);//    [C@1950198
                char [] chs = (char[]) field.get(s);//此时就已经得到了字符串中存储字符的那个数组的对象了.
                //System.out.println(Arrays.toString(chs));
                chs[0] = 'Q';
                System.out.println(s);



字符串在正常情况下是不可以改变的.
但是在底层字符串是用  private final 修饰的一个 char 类型的数组.这个数组的名字是 value[];
没有对外提供对应的getXXX和setXXX的方法,所以说,外界无法获取到value这个数组的对象,无法变更
又因为是用final修饰的,value这个变量记录的地址值是无法改变的.


但是换句话来讲,如果我们能得到数组的对象.虽然他是用final修饰的,不能改变地址值
但是可以修改内部的属性值.(可以改变内部的元素)
所以用反射的知识点,获取到value对象,然后对数组的索引上的值就可以修改了.



(三)通过无参构造创建对象
1        通过无参构造创建Person类的对象
        //通过Class类中的newInstance()方法直接创建无参的对象.是一种简化的写法.
        Class clazz = Class.forName("com.heima.bean.Person");        //先要获取字节码文件的对象
        Person p = (Person) clazz.newInstance();                                //通过无参构造创建对象
        以上的两行代码等同于
        Person p = new Person();



        用Constructor通过无参构造创建对象
        Class clazz = Class.forName("com.itheima_01_bean.Bean");
        Constructor cons = clazz.getConstructor();//可变参数可以什么都不传,此时就跟无参构造匹配
        Object obj = cons.newInstance();



        通过私有的无参构造创建对象  //非public
        Class clazz = Class.forName("com.heima.demo.Student");
        Constructor c = clazz.getDeclaredConstructor();
        c.setAccessible(true);
        Student s = (Student) c.newInstance();
        System.out.println(s);


(四)通过有参构造创建对象

2        通过有参构造创建Person类的对象
        Class clazz = Class.forName("com.heima.bean.Person");        //先要获取字节码文件的对象
        Constructor c = clazz.getConstructor(String.class,int.class);//通过这个字节码文件的对象,来获取有参构造
        Person p = (Person) c.newInstance("张三",23);                                                //通过有参构造创建对象
       
        以上三行代码等同于
        Person p = new Person("张三",23);
       
        //上面的是通过反射,class文件创建的对象
        //下面的是通过java文件,常规方式创建的对象.



        通过私有的有参构造创建对象  //非public
        Class clazz = Class.forName("com.heima.demo.Student");
        Constructor c = clazz.getDeclaredConstructor(String.class,int.class);
        c.setAccessible(true);
        Student s = (Student) c.newInstance("张三",20);
        System.out.println(s);






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