Home >Java >JavaBase >Insight String string

Insight String string

coldplay.xixi
coldplay.xixiforward
2020-12-28 17:27:032224browse

java basic tutorialColumn introduction Insight String string

Insight String string

##Recommended (free): java basic tutorial

Implementation principle

in Java6 and In the previous version, the String object was an object that encapsulated the char array. It mainly had four member variables: char array, offset offset, character count, and hash value hash.

From Java7 to Java8, there are no longer offset and count variables in the String class. The advantage of this is that the String object takes up slightly less memory.

Starting from the Java9 version, the char[] field has been changed to the byte[] field, and a new attribute coder has been maintained, which is an identifier of the encoding format.

A char character occupies 16 bits and 2 bytes. In this case, storing characters in a single-byte encoding (characters occupying one byte) is very wasteful. In order to save memory space, the String class of JDK1.9 uses an 8-bit, 1-byte byte array to store strings.

The function of the new attribute coder is that when calculating the string length or using the indexOf() function, we need to determine how to calculate the string length based on this field. The coder attribute has two values ​​by default: 0 and 1. 0 represents Latin-1 (single-byte encoding) and 1 represents UTF-16. If String determines that the string contains only Latin-1, the coder attribute value is 0, otherwise it is 1.

Immutable

Looking at the code of the String class, we can find that the String class is modified by the final keyword, so this class cannot be inherited, and The variable char array in the String class is also modified by final, so the String object cannot be modified.

The immutability of String objects mainly has the following advantages:

First, ensure the security of String objects. Assuming that the String object is mutable, the String object may be maliciously modified.

Second, it ensures that the hash attribute value will not change frequently, ensuring uniqueness, so that containers similar to HashMap can implement the corresponding key-value cache function.

Third, you can implement a string constant pool.

In Java, there are usually two ways to create string objects:

The first is to create it through a string constant, such as

String str = "abc".

The second is to create a string variable in the form of new, such as

String str = new String("abc").

When the first method is used to create a string object in the code, when compiling the class file, the "abc" constant string will be put into the constant structure. When the class is loaded, "abc" will will be created in the constant pool; str will then refer to a string object in the constant pool. This method can reduce the repeated creation of string objects with the same value and save memory.

String str = new String("abc") In this way, first when compiling the class file, the "abc" constant string will be put into the constant structure. In the class When loading, "abc" will be created in the constant pool; secondly, when calling new, the JVM command will call the constructor of String, and the char array in the String object will reference the "abc" character in the constant pool String char array, create a String object in the heap memory; finally, str will refer to the String object, and the reference of the String object is different from the reference of the "abc" string in the constant pool.

Objects and references: The content of the object is stored in the memory. The operating system finds the stored content through the memory address. The reference refers to the memory address.

For example:

String str = new String("abc"), the variable str points to the storage address of the String object, which means that str is not an object, but just an object reference.

String concatenation

Constant addition

String str = "ab" + "cd" + "ef";
View Compiled bytecode

0 ldc #2 <abcdef>2 astore_13 return
It can be found that the compiler optimizes the code as follows

String str= "abcdef";

Variable addition

String a = "ab";String b = "cd";String c = a + b;
View the compiled bytecode

 0 ldc #2 <ab>
 2 astore_1 3 ldc #3 <cd>
 5 astore_2 6 new #4 <java/lang/StringBuilder>
 9 dup10 invokespecial #5 <java/lang/StringBuilder.<init>>13 aload_114 invokevirtual #6 <java/lang/StringBuilder.append>17 aload_218 invokevirtual #6 <java/lang/StringBuilder.append>21 invokevirtual #7 <java/lang/StringBuilder.toString>24 astore_325 return
It can be found that when Java adds strings, the bottom layer uses StringBuilder, and the code is optimized as follows:

String c = new StringBuilder().append("ab").append("cd").toString();

String.intern

String a = new String("abc").intern();String b = new String("abc").intern();System.out.print(a == b);
Output result:

true
In the string

constant, the object will be placed by default into the constant pool. For example: String a = "123"

在字符串变量中,对象是会创建在堆内存中,同时也会在常量池中创建一个字符串对象,String 对象中的 char 数组将会引用常量池中的 char 数组,并返回堆内存对象引用。例如:String b = new String("abc")

如果调用 intern 方法,会去查看字符串常量池中是否有等于该对象的字符串的引用,如果没有,在 JDK1.6 版本中会复制堆中的字符串到常量池中,并返回该字符串引用,堆内存中原有的字符串由于没有引用指向它,将会通过垃圾回收器回收。

在 JDK1.7 版本以后,由于常量池已经合并到了堆中,所以不会再复制具体字符串了,只是会把首次遇到的字符串的引用添加到常量池中;如果有,就返回常量池中的字符串引用。

下面开始分析上面的代码块:

在一开始字符串”abc”会在加载类时,在常量池中创建一个字符串对象。

创建 a 变量时,调用 new Sting() 会在堆内存中创建一个 String 对象,String 对象中的 char 数组将会引用常量池中字符串。在调用 intern 方法之后,会去常量池中查找是否有等于该字符串对象的引用,有就返回常量池中的字符串引用。

创建 b 变量时,调用 new Sting() 会在堆内存中创建一个 String 对象,String 对象中的 char 数组将会引用常量池中字符串。在调用 intern 方法之后,会去常量池中查找是否有等于该字符串对象的引用,有就返回常量池中的字符串引用。

而在堆内存中的两个String对象,由于没有引用指向它,将会被垃圾回收。所以 a 和 b 引用的是同一个对象。

如果在运行时,创建字符串对象,将会直接在堆内存中创建,不会在常量池中创建。所以动态创建的字符串对象,调用 intern 方法,在 JDK1.6 版本中会去常量池中创建运行时常量以及返回字符串引用,在 JDK1.7 版本之后,会将堆中的字符串常量的引用放入到常量池中,当其它堆中的字符串对象通过 intern 方法获取字符串对象引用时,则会去常量池中判断是否有相同值的字符串的引用,此时有,则返回该常量池中字符串引用,跟之前的字符串指向同一地址的字符串对象。

以一张图来总结 String 字符串的创建分配内存地址情况:

使用 intern 方法需要注意的一点是,一定要结合实际场景。因为常量池的实现是类似于一个 HashTable 的实现方式,HashTable 存储的数据越大,遍历的时间复杂度就会增加。如果数据过大,会增加整个字符串常量池的负担。

判断字符串是否相等

// 运行环境 JDK1.8String str1 = "abc";String str2 = new String("abc");String str3= str2.intern();System.out.println(str1==str2); // falseSystem.out.println(str2==str3); // falseSystem.out.println(str1==str3); // true
// 运行环境 JDK1.8String s1 = new String("1") + new String("1");s1.intern();String s2 = "11";System.out.println(s1 == s2); // true , 如果不执行1.intern(),则返回false

String s1 = new String("1") + new String("1")会在堆中组合一个新的字符串对象"11",在s1.intern()之后,由于常量池中没有该字符串的引用,所以常量池中生成一个堆中字符串"11"的引用,此时String s2 = "11"返回的是堆字符串"11"的引用,所以s1==s2

在JDK1.7版本以及之后的版本运行以下代码,你会发现结果为true,在JDK1.6版本运行的结果却为false:

String s1 = new String("1") + new String("1");System.out.println( s1.intern()==s1);

StringBuilder与StringBuffer

由于String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。

和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的对象

StringBuilder 类在 Java 5 中被提出,它和 StringBuffer 之间的最大不同在于 StringBuilder 的方法不是线程安全的(不能同步访问)。

由于 StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类。然而在应用程序要求线程安全的情况下,则必须使用 StringBuffer 类。

The above is the detailed content of Insight String string. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:learnku.com. If there is any infringement, please contact admin@php.cn delete