A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

【南京校区】反射的妙用(二)

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

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



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

   
[AppleScript] 纯文本查看 复制代码
利用反射运行一个私有的方法									|	对比 public 修饰的方法[/align]
	// 获取字节码对象									    |
	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);

0 个回复

您需要登录后才可以回帖 登录 | 加入黑马