黑马程序员技术交流社区

标题: 用反射改变字符串,为什么有的可变,有的不可变 [打印本页]

作者: 奚华    时间: 2012-11-18 10:39
标题: 用反射改变字符串,为什么有的可变,有的不可变
大家看下面的两段代码,微小的差别,但结果截然相反,跪求真相,跪求解释!!!!!

1、使用反射改变传入change方法的对象的final String str成员,我们在声明str时就给str赋值为"ABC":str没被改变仍为"ABC"
  1. import java.lang.reflect.Field;


  2. public class ReflectTest {
  3.         private final  String str="ABC";//声明时赋值
  4.        

  5.         /**
  6.          * @param args
  7.          * @throws Exception
  8.          */
  9.         public static void main(String[] args) throws Exception {
  10.                 // TODO Auto-generated method stub
  11.                 ReflectTest rt=new ReflectTest();
  12.                
  13.                 System.out.println("---打印改变前的str字符串的值---");
  14.                 System.out.println(rt.str);//打印出来ABC
  15.                
  16.                 rt.change(rt);
  17.                
  18.                 System.out.println("---打印改变后的str字符串的值---");
  19.                 System.out.println(rt.str);//打印出来是ABC
  20.         }
  21.        
  22.        
  23.         /**
  24.          * 试图改变obj对象里的的字符串成员
  25.          * @param obj
  26.          * @throws Exception
  27.          */
  28.         public void change(Object obj) throws Exception
  29.         {
  30.                 Field[] fild=obj.getClass().getDeclaredFields();
  31.                 for(Field f:fild)
  32.                 {
  33.                         if(!f.isAccessible())//设置权限
  34.                                 f.setAccessible(true);
  35.                         if(f.getType()==String.class)
  36.                         {
  37.                                 String str=new String("CBA");//想把这些字符串设置为"CBA"
  38.                                 f.set(obj, str);
  39.                         }
  40.                 }
  41.         }

  42. }
复制代码
2、使用反射改变传入change方法的对象的final String str成员,我们在声明str时并没有给str赋值,接着我使用一个初始化块给str赋值为"ABC",大家擦亮眼睛看结果:str被改变了被变为了"CBA"
  1. import java.lang.reflect.Field;


  2. public class ReflectTest {
  3.       private final  String str;//声明时不赋值,在下面的初始化块中赋值!
  4.        
  5.       //给str赋值为"ABC"
  6.       {
  7.             str="ABC";
  8.       }

  9.       /**
  10.       * @param args
  11.       * @throws Exception
  12.       */
  13.        public static void main(String[] args) throws Exception {
  14.             // TODO Auto-generated method stub
  15.              ReflectTest rt=new ReflectTest();
  16.                
  17.       System.out.println("---打印改变前的str字符串的值---");
  18.       System.out.println(rt.str);//打印出来ABC
  19.                
  20.       rt.change(rt);
  21.                
  22.       System.out.println("---打印改变后的str字符串的值---");
  23.       System.out.println(rt.str);//打印出来是CBA
  24.         }
  25.        
  26.        
  27.         /**
  28.          * 试图改变obj对象里的的字符串成员
  29.          * @param obj
  30.          * @throws Exception
  31.          */
  32.         public void change(Object obj) throws Exception
  33.         {
  34.       Field[] fild=obj.getClass().getDeclaredFields();
  35.       for(Field f:fild)
  36.       {
  37.             if(!f.isAccessible())//设置权限
  38.             f.setAccessible(true);
  39.             if(f.getType()==String.class)
  40.             {
  41.                    String str=new String("CBA");//想把这些字符串设置为"CBA"
  42.                    f.set(obj, str);
  43.            }
  44.       }
  45.         }
  46. }
复制代码
求解释,求真像!



作者: 李刚    时间: 2012-11-21 23:00
private final  String str="ABC";//声明时赋值
这里创建的是对象吧,“ABC”在堆内存中。所以不能改变。
private final  String str;//声明时不赋值,在下面的初始化块中赋值!

        

      //给str赋值为"ABC"

      {

            str="ABC";

      }

这里的,“ABC”在栈内存中吧,没有创建对象。
String str=new String("CBA");//想把这些字符串设置为"CBA"

                   f.set(obj, str);

这里重新创建了对象,其实就是两个str同时指向了new String("CBA");

个人观点
作者: 李刚    时间: 2012-11-23 18:50
public class ReflectTest3 {

        private final  String str="ABC";
       
        /*
         * public ReflectTest3(String str){ this.str=str; }
         */

        public String getStr() {
                return str;
        }

        /**
         *
         * @param args
         *
         * @throws Exception
         */

        public static void main(String[] args) throws Exception {

                // TODO Auto-generated method stub

                ReflectTest3 rt = new ReflectTest3();

                System.out.println("---打印改变前的str字符串的值---");

                System.out.println(rt.str);// 打印出来ABC
               
                System.out.println(rt.str.hashCode());

                rt.change(rt.str);

                System.out.println("---打印改变后的str字符串的值---");

                System.out.println(rt.str);// 打印出来还是ABC,没有被改变
                System.out.println(rt.str.hashCode());
        }

        /**
         *
         * 试图改变obj对象里的的字符串成员
         *
         * @param obj
         *
         * @throws Exception
         */

         public void change(String str) throws Exception

     {

                    Class cls = str.getClass();// 获得str的Class对象

                        Field fil = cls.getDeclaredField("value");// 获得String类中的char数组value[]的Filed变量

                        fil.setAccessible(true);// 由于value变量是一个private的所以设置权限

                        char[] ch = { 'D', 'S', 'W', 'Q' };

                        fil.set(str, ch);// 改变value所指向的数组,使value指向ch数组


     }

}


这个输出结果可以改变private final  String str="ABC";的值,final好像只是能够使对象的hashCode值不变。




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