Why not change the String object

Reprinted: https: //www.cnblogs.com/leskang/p/6110631.html

First, what is an immutable object?

        As we all know, in Java in, String class object is immutable. So in the end what is immutable objects? Can be considered: If an object after it is created, can not change its state, then the object is immutable. Means that the state can not be changed, can not be changed in the member variable objects, including basic data type value can not be changed, the variable reference type can not point to other objects (final modification), the type state of an object reference pointing to not change.

 

Second, the distinction between objects and object references

For Java beginner, for String objects are immutable there is always a doubt. Look at the code below:

String s = "ABCabc";
System.out.println("s = " + s);
s = "123456";
System.out.println("s = " + s);

 Print results: s = ABCabc

s = 123456

first create a String object s, and then let the value of s is "ABCabc", and then letting s is "123456." As can be seen from the printed results, it does change the value of s. So how String objects are immutable said it? In fact, there is a misunderstanding here: s just a String object reference, not the object itself . The object is a memory area in the memory, the more the member variables, the greater this memory area occupied space. References only a 4-byte data, stored inside the object it points to the address of the object can be accessed via this address. That, s just a reference that points to a specific object, when s = "123456"; After this code executed, and create a new object "123456" and a reference point to the re s heart object, the original object "ABCabc" still heap in existence, it has not changed. Memory structure as shown below:

 tips: One difference between Java and C ++ is that direct manipulation object itself is impossible in Java, all objects referenced by a point, must pass this reference to access the object itself, including the value of the acquisition member variables change member objects variable, call the object's methods. And there is a reference in C ++, objects and pointers three things, three things can access the object. In fact, the pointer reference in Java and C ++ are conceptually similar, the object of their address values are stored in memory, but in Java, citing lost some flexibility, such as references in Java can not be like addition and subtraction is performed as in C ++ pointer

Third, why String objects are immutable?

To understand the immutability of String, first look at what are the String class member variables. In JDK1.6, String member variables are the following:
Copy the code
public final class String
    implements java.io.Serializable, Comparable<string>, CharSequence{
    /** The value is used for character storage. */
    private final char value[];
 
    /** The offset is the first index of the storage that is used. */
    private final int offset;
 
    /** The count is the number of characters in the String. */
    private final int count;
 
    /** Cache the hash code for the string */
    private int hash; // Default to 0</string>
Copy the code
In JDK1.7, String class made some changes, mainly to change the behavior of the substring method of execution, and this is not related to the theme of this article. JDK1.7 main member variable of the String class on the remaining two:
Copy the code
public final class String
    implements java.io.Serializable, Comparable<string>, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
 
    /** Cache the hash code for the string */
    private int hash; // Default to 0</string>
Copy the code
As can be seen from the above code, in fact, the package of the array of characters String class in Java. In JDK6, value is the String array package, offset is the starting location of this value in String array, count is the number of occupied String character. In JDK7, only one variable value, which is the value of all the characters belong to this String object. This change does not affect this discussion. In addition there are a hash member variable is cached hash value of the String object, and this has nothing to member variables discussed herein. In Java, arrays are objects (java I can refer to the characteristics of the article before the array). So the value is only a reference , it points to a real array object. In fact, the implementation of the String s = "ABCabc"; After this code, the real memory layout should look like this: \

value, offset and count these three variables are private, and does not provide setValue, setOffset and setCount other public methods to modify these values can not be edited in an external String String class. That can not be changed once initialized, and can not be accessed outside of the three members of the String class. In addition, value, offset and count these three variables are final, that is inside the String class, once these three values initialized and can not be changed. It can be considered String objects are immutable up. 
So in a String, obviously there are some methods, call the changed value they can get. These methods include substring, replace, replaceAll, toLowerCase like. For example the following code:
String a = "ABCabc";
System.out.println("a = " + a);
a = a.replace('A', 'a');
System.out.println("a = " + a);

 Print results: a = ABCabc

a = aBCabc

then the value of a seemingly changed, it is still the same errors. Again, a reference to a just, is not a true string object, when calling a.replace ( 'A', 'a '), the internal method creates a new String object , and this new
object is re-assigned a reference to a. String replace method in the source code can describe the problem
 
读者可以自己查看其他方法,都是在方法内部重新创建新的String对象,并且返回这个新的对象,原来的对象是不会被改变的。这也是为什么像replace, substring,toLowerCase等方法都存在返回值的原因。也是为什么像下面这样调用不会改变对象的值: 
String ss = "123456";
System.out.println("ss = " + ss);
ss.replace('1', '0');
System.out.println("ss = " + ss);

 打印结果: ss = 123456

ss = 123456

四、String对象真的不可变吗?

从上文可知String的成员变量value是private final 的,也就是初始化之后不可改变。那么在这几个成员中, value比较特殊,因为他是一个引用变量,而不是真正的对象。value是final修饰的,也就是说final不能再指向其他数组对象,那么我能改变value指向的数组吗? 比如将数组中的某个位置上的字符变为下划线“_”。 至少在我们自己写的普通代码中不能够做到,因为我们根本不能够访问到这个value引用(private修饰),更不能通过这个引用去修改数组。 那么用什么方式可以访问私有成员呢? 没错,用反射, 可以反射出String对象中的value属性, 进而改变通过获得的value引用改变数组的结构。下面是实例代码: 

Copy the code
public static void testReflection() throws Exception {
     
    //创建字符串"Hello World", 并赋给引用s
    String s = "Hello World"; 
     
    System.out.println("s = " + s); //Hello World
     
    //获取String类中的value字段
    Field valueFieldOfString = String.class.getDeclaredField("value");
     
    //改变value属性的访问权限
    valueFieldOfString.setAccessible(true);
     
    //获取s对象上的value属性的值
    char[] value = (char[]) valueFieldOfString.get(s);
     
    //改变value所引用的数组中的第5个字符
    value[5] = '_';
     
    System.out.println("s = " + s);  //Hello_World
}
Copy the code

打印结果为: s = Hello World

s = Hello_World

       with a String object in this process, s always cited, but then reflected back and forth, the String object has changed, that is, by reflection can be modified so-called "immutable" object. But generally we do not do. This reflected instance can also indicate a problem: If an object, other objects of his state combination can not change, but the object is probably not immutable. For example, a Car object, which combines a Wheel object Wheel although this statement has become the object of private final, but the state of the Wheel inside the object can be changed, then we can not guarantee a good Car immutable objects.
 

Guess you like

Origin www.cnblogs.com/parrot/p/11512162.html