Differences in JAVA stack
Author:Eve Cole
Update Time:2009-11-30 17:08:19
-
1. Stack and heap are places used by Java to store data in Ram. Unlike C++, Java automatically manages the stack and heap, and programmers cannot directly set the stack or heap.
2. The advantage of the stack is that the access speed is faster than the heap, second only to the registers directly located in the CPU. But the disadvantage is that the size and lifetime of the data stored in the stack must be determined and there is a lack of flexibility. In addition, stack data can be shared, see point 3 for details. The advantage of the heap is that it can dynamically allocate memory size, and the lifetime does not need to be told to the compiler in advance. Java's garbage collector will automatically collect the data that is no longer used. But the disadvantage is that due to the need to dynamically allocate memory at runtime, the access speed is slow.
3. There are two types of data types in Java.
One is primitive types, there are 8 types in total, namely int, short, long, byte, float, double, boolean, char (note that there is no basic type of string). This type of definition is defined in the form such as int a = 3; long b = 255L; and is called an automatic variable. It is worth noting that automatic variables store literal values, not instances of classes, that is, they are not references to classes. There is no class here. For example, int a = 3; where a is a reference pointing to the int type, pointing to the literal value 3. The data of these literal values are known in size and lifetime (these literal values are fixedly defined in a certain program block, and the field values disappear after the program block exits). For the sake of speed, they exist on the stack. .
In addition, the stack has a very important special feature, that is, the data stored in the stack can be shared. Suppose we also define:
int a = 3;
int b = 3;
The compiler first processes int a = 3; first it creates a reference to the variable a on the stack, and then searches for an address with a literal value of 3. If it does not find it, it opens an address to store the literal value of 3, and then a points to the address of 3. Next, int b = 3 is processed; after creating the reference variable of b, since there is already a literal value of 3 on the stack, b is directly pointed to the address of 3. In this way, there is a situation where a and b both point to 3 at the same time.
It is important to note that the reference of this literal value is different from the reference of the class object. Assume that the references of two class objects point to the same object at the same time. If one object reference variable modifies the internal state of the object, then the other object reference variable will immediately reflect the change. In contrast, modifying the value of a literal reference does not cause the value of another reference to the literal to also change. As in the above example, after we define the values of a and b, we then set a=4; then, b will not be equal to 4, but still equal to 3. Inside the compiler, when it encounters a = 4;, it will re-search whether there is a literal value of 4 on the stack. If not, it will re-open an address to store the value of 4; if it already exists, it will directly point a to this address. . Therefore, changes in the value of a will not affect the value of b.
The other is wrapper class data, such as Integer, String, Double and other classes that wrap the corresponding basic data types. All these types of data exist in the heap. Java uses the new () statement to explicitly tell the compiler that it will be dynamically created as needed at runtime, so it is more flexible, but the disadvantage is that it takes up more time. 4. String is a special wrapper type data. That is, it can be created in the form of String str = new String( "abc" );, or it can be created in the form of String str = "abc" ; (for comparison, before JDK 5.0, you have never seen Integer i = 3; expression, because classes and literal values cannot be used interchangeably, except for String. In JDK 5.0, this expression is possible! Because the compiler performs the conversion of Integer i = new Integer(3) in the background) . The former is a standardized class creation process, that is, in Java, everything is an object, and objects are instances of classes, all created in the form of new (). Some classes in Java, such as the DateFormat class, can return a newly created class through the getInstance() method of the class, which seems to violate this principle. Not really. This class uses the singleton pattern to return an instance of the class, but this instance is created inside the class through new (), and getInstance() hides this detail from the outside. Then why in String str = "abc" ;, the instance is not created through new (). Does it violate the above principle? Actually no.
5. About the inner workings of String str = "abc". Java internally converts this statement into the following steps:
(1) First define an object reference variable named str to the String class: String str;
(2) Search the stack to see if there is an address with a value of "abc". If not, open an address with a literal value of "abc", then create a new object o of the String class, and add the characters of o The string value points to this address, and the referenced object o is recorded next to this address on the stack. If there is already an address with the value "abc", the object o is found and the address of o is returned.
(3) Point str to the address of object o.
It is worth noting that generally the string values in the String class are stored directly. But like String str = "abc"; in this case, the string value saves a reference to the data stored on the stack!
In order to better illustrate this problem, we can verify it through the following codes.
String str1 = "abc" ;
String str2 = "abc" ;
System.out.println(str1==str2); //true
Note that we do not use str1.equals(str2); here, because this will compare whether the values of the two strings are equal. == sign, according to JDK instructions, only returns true when both references point to the same object. What we want to see here is whether str1 and str2 both point to the same object.
The results show that the JVM created two references str1 and str2, but only created one object, and both references pointed to this object.
Let’s go one step further and change the above code to:
String str1 = "abc" ;
String str2 = "abc" ;
str1 = "bcd" ;
System.out.println(str1 + "," + str2); //bcd, abc
System.out.println(str1==str2); //false
This means that the change in assignment results in a change in the class object reference, and str1 points to another new object! And str2 still points to the original object. In the above example, when we changed the value of str1 to "bcd", the JVM found that there was no address to store this value on the stack, so it opened this address and created a new object whose string value points to this address.
In fact, the String class is designed to be immutable. If you want to change its value, you can, but the JVM quietly creates a new object based on the new value at runtime, and then returns the address of this object to a reference to the original class. Although this creation process is completely automated, it takes up more time after all. In an environment that is sensitive to time requirements, it will have certain adverse effects.
Modify the original code again:
String str1 = "abc" ;
String str2 = "abc" ;
str1 = "bcd" ;
String str3 = str1;
System.out.println(str3); //bcd
String str4 = "bcd" ;
System.out.println(str1 == str4); //true
The reference to the object str3 points directly to the object pointed to by str1 (note that str3 does not create a new object). After str1 changes its value, create a String reference str4 and point to the new object created because str1 modified the value. It can be found that str4 did not create a new object this time, thus realizing the sharing of data in the stack again.
Let's look at the following code again.
String str1 = new String( "abc" );
String str2 = "abc" ;
System.out.println(str1==str2); //false
Two references are created. Two objects are created. The two references point to two different objects respectively.
String str1 = "abc" ;
String str2 = new String( "abc" );
System.out.println(str1==str2); //false
Two references are created. Two objects are created. The two references point to two different objects respectively.
The above two pieces of code illustrate that as long as new () is used to create a new object, it will be created in the heap, and its string value is stored separately. Even if it is the same as the data in the stack, it will not be shared with the data in the stack. .
6. The value of the data type wrapper class cannot be modified. Not only the value of the String class cannot be modified, but all data type wrapper classes cannot change their internal values. 7. Conclusion and suggestions:
(1) When we define a class using a format such as String str = "abc";, we always take it for granted that we create an object str of the String class. Worry about traps! The object may not have been created! The only thing that is certain is that a reference to the String class is created. As for whether this reference points to a new object, it must be considered according to the context, unless you explicitly create a new object through the new () method. Therefore, a more accurate statement is that we create a reference variable str that points to an object of the String class. This object reference variable points to a String class with a value of "abc". A clear understanding of this is very helpful in eliminating hard-to-find bugs in the program.
(2) Using String str = "abc"; can improve the running speed of the program to a certain extent, because the JVM will automatically determine whether it is necessary to create a new object based on the actual situation of the data in the stack. As for the code of String str = new String("abc");, new objects are always created in the heap, regardless of whether their string values are equal or whether it is necessary to create new objects, thus increasing the burden on the program. This idea should be the idea of flyweight mode, but it is unknown whether the internal implementation of JDK applies this mode.
(3) When comparing whether the values in the packaging class are equal, use the equals() method; when testing whether the references of two packaging classes point to the same object, use ==.
(4) Due to the immutable nature of the String class, when the String variable needs to frequently change its value, you should consider using the StringBuffer class to improve program efficiency.