Introduction
This article will explain several properties of string.
One, the immutability of string
For beginners, it is easy to mistakenly think that a string object can be changed, especially when the + link, the object seems to really change. However, a string object cannot be modified once it is created. Next, we step-by-step analysis of how a string maintains its immutable nature ;
1. Means one: Final class and final private member
Let's take a look at some of the source code of string:
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 /** use serialVersionUID from JDK 1.0.2 for interoperability */ private static final long serialVersionUID = -6849794470754667710L; }
?? We can find that the string is a final class, and that 3 members are private , which means that string cannot be inherited, which prevents the programmer from inheriting the method of rewriting the string class to make the string class "mutable".
?? From source discovery, each string object maintains a char array-Private member value. The array value is the underlying array of string, which is used to store the contents of the string, and is private final , but the array is a reference type, so only the reference does not change, meaning that the value of the array element can be changed, and string There is a constructor that can pass in the array, so could we "modify" the contents of the String by modifying the outer char array element?
Let's do an experiment, as follows:
public static void main(String[] args) { char[] arr = new char[]{‘a‘,‘b‘,‘c‘,‘d‘}; String str = new String(arr); arr[3]=‘e‘; System.out.println("str= "+str); System.out.println("arr[]= "+Arrays.toString(arr)); }
Run results
str= ABCD
arr[]= [A, B, C, E]
?? The result is different from what we think. The string str uses an array of arr to construct an object, and when the array arr modifies its element value, the string str does not follow the change. Let's take a look at how this construction method is handled:
public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }
?? The original string when constructing an object using an outer char array, is a copy of an external char array , so that changes to the outer char array are not affected to the string object.
2. Means II: Changing the way that objects are created
?? From the above analysis we know that we are unable to modify the string object from the outside, it is impossible to use the method provided by string, because there are a number of methods that seem to be able to change the string object, such as,, and replace()
replaceAll()
substring()
so on. substring()
For example, let's take a look at the source code:
public String substring(int beginIndex, int endIndex) { //........ return ((beginIndex == 0) && (endIndex == value.length)) ? this : new String(value, beginIndex, subLen); }
As you can see from the source, if you do not cut the entire string, you will create a new object. That is, as long as the original string is not equal, a new string object is created .
Extended
The basic type of wrapper class is similar to string, which is the final class, an immutable object, and a private final member that maintains a stored content. such as the Integer class:
public final class Integer extends Number implements Comparable<Integer> { private final int value;}
Second, string + operations vs. constant pool of strings
Let's first look at an example:
public class MyTest { public static void main(String[] args) { String s = "Love You"; String s2 = "Love"+" You"; String s3 = s2 + ""; String s4 = new String("Love You"); System.out.println("s == s2 "+(s==s2)); System.out.println("s == s3 "+(s==s3)); System.out.println("s == s4 "+(s==s4)); }}
Operation Result:
s = = S2? True
s = = S3? false
s = = S4? false
?? is not very puzzled about the running result. Don't worry, let's get this straight. First, we need to know that the compiler has the advantage of optimizing the code as much as possible during compilation, so the calculations that can be done by the compiler do not wait for the run-time calculation, and the calculation of the usual expression is done during compilation . So, the result of S2 is actually calculated during compilation, as is the value of S, so the two are equal, that is, literal constants, which are created and maintained in the string constant pool when the class is loaded. However, the S3 expression contains variable s2, which can only be run to perform the calculation, that is, the results are evaluated at run time, and objects are created in the heap and are not naturally equal to S. Instead, S4 uses new to create objects directly in the heap, which is more unlikely to be equal.
?? How does the + link operation of string be done during the run, knowing that the string object is an immutable object. We use the Jad command Jad Mytest.class to decompile the above example's CALSS file back to the Java code to see exactly how it was implemented:
public class MyTest{ public MyTest() { } public static void main(String args[]) { String s = "Love You"; String s2 = "Love You";//已经得到计算结果 String s3 = (new StringBuilder(String.valueOf(s2))).toString(); String s4 = new String("Love You"); System.out.println((new StringBuilder("s == s2 ")).append(s == s2).toString()); System.out.println((new StringBuilder("s == s3 ")).append(s == s3).toString()); System.out.println((new StringBuilder("s == s4 ")).append(s == s4).toString()); }}
?? As you can see, the compiler handles the + number as a StringBuilder.append()
method. That is, during run time, the calculation of the link string is done by creating the StringBuilder object, calling the append()
method, and the expression for each link string is to create a StringBuilder object. For this reason , you should consider using StringBuilder instead of the + link in order to repeatedly execute string links in the loop, avoiding the performance overhead of creating StringBuilder repeatedly.
string constant Pool
A constant pool can refer to my previous article, which does not go deep, but only the parts related to string.
?? The contents of a string constant pool are mostly derived from compiled string literal constants. will also increase during operation,
String Intern ():
Returns a normalized representation of a string object.
An initially empty string pool, which is privately maintained by the class string.
When the Intern method is called, if the pool already contains a string equal to this string object (as determined by the Equals (Object) method), the string in the pool is returned. Otherwise, this string object is added to the pool and a reference to this string object is returned.
It follows the following rules: For any two strings s and T, s.intern () = = T.intern () is true if and only if S.equals (t) is true.
Another notable point is that although the return value of String.intern () is always equal to the string constant. But this does not mean that the intern () return of the same string will be the same in every moment of the system (although in the case of more than 95%, it is the same). Because there is a possibility: after a intern () call, the string is recycled at some point, and then a intern () call is made, then the literal string is re-added to the constant pool, but the reference location is different.
Iii. hashcode () method of String
?? String is also the standard of compliance with equals, which is s.equals(s1)
true, s.hashCode()==s1.hashCode()
or True. The Eqauls method is not a concern here, but hashCode()
it is a way of explaining it, String.hashCode()
a bit of meaning, and may be asked during an interview. First look at the code:
public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value; for (int i = 0; i < value.length; i++) { h = 31 * h + val[i]; } hash = h; } return h; }
# #为什么要选31作为乘数呢?
From the information on the Internet, there are generally the following two reasons:
31 is a moderate prime number, which is one of the preferred prime numbers for the hashcode multiplier. Other similar prime numbers, such as 37, 41, 43 and so on, are also good choices. So why did you choose 31? Please see the second reason.
- 31 can be optimized by JVM, * i = (i << 5)-I.
Source: http://www.cnblogs.com/jinggod/p/8425182.html
The article is inappropriate, please correct me, you can also pay attention to my public number: 好好学java
, access to high-quality resources.
Java Fundamentals (v) deep parsing of string properties