java basic tutorialColumn introduction 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 asString str = "abc".
String str = new String("abc").
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.
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?returnIt 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?returnIt 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:
trueIn the string
constant, the object will be placed by default into the constant pool. For example: String a = "123"
在字符串變量中,對(duì)象是會(huì)創(chuàng)建在堆內(nèi)存中,同時(shí)也會(huì)在常量池中創(chuàng)建一個(gè)字符串對(duì)象,String 對(duì)象中的 char 數(shù)組將會(huì)引用常量池中的 char 數(shù)組,并返回堆內(nèi)存對(duì)象引用。例如:String b = new String("abc")
如果調(diào)用 intern 方法,會(huì)去查看字符串常量池中是否有等于該對(duì)象的字符串的引用,如果沒(méi)有,在 JDK1.6 版本中會(huì)復(fù)制堆中的字符串到常量池中,并返回該字符串引用,堆內(nèi)存中原有的字符串由于沒(méi)有引用指向它,將會(huì)通過(guò)垃圾回收器回收。
在 JDK1.7 版本以后,由于常量池已經(jīng)合并到了堆中,所以不會(huì)再?gòu)?fù)制具體字符串了,只是會(huì)把首次遇到的字符串的引用添加到常量池中;如果有,就返回常量池中的字符串引用。
下面開(kāi)始分析上面的代碼塊:
在一開(kāi)始字符串”abc”會(huì)在加載類(lèi)時(shí),在常量池中創(chuàng)建一個(gè)字符串對(duì)象。
創(chuàng)建 a 變量時(shí),調(diào)用 new Sting() 會(huì)在堆內(nèi)存中創(chuàng)建一個(gè) String 對(duì)象,String 對(duì)象中的 char 數(shù)組將會(huì)引用常量池中字符串。在調(diào)用 intern 方法之后,會(huì)去常量池中查找是否有等于該字符串對(duì)象的引用,有就返回常量池中的字符串引用。
創(chuàng)建 b 變量時(shí),調(diào)用 new Sting() 會(huì)在堆內(nèi)存中創(chuàng)建一個(gè) String 對(duì)象,String 對(duì)象中的 char 數(shù)組將會(huì)引用常量池中字符串。在調(diào)用 intern 方法之后,會(huì)去常量池中查找是否有等于該字符串對(duì)象的引用,有就返回常量池中的字符串引用。
而在堆內(nèi)存中的兩個(gè)String對(duì)象,由于沒(méi)有引用指向它,將會(huì)被垃圾回收。所以 a 和 b 引用的是同一個(gè)對(duì)象。
如果在運(yùn)行時(shí),創(chuàng)建字符串對(duì)象,將會(huì)直接在堆內(nèi)存中創(chuàng)建,不會(huì)在常量池中創(chuàng)建。所以動(dòng)態(tài)創(chuàng)建的字符串對(duì)象,調(diào)用 intern 方法,在 JDK1.6 版本中會(huì)去常量池中創(chuàng)建運(yùn)行時(shí)常量以及返回字符串引用,在 JDK1.7 版本之后,會(huì)將堆中的字符串常量的引用放入到常量池中,當(dāng)其它堆中的字符串對(duì)象通過(guò) intern 方法獲取字符串對(duì)象引用時(shí),則會(huì)去常量池中判斷是否有相同值的字符串的引用,此時(shí)有,則返回該常量池中字符串引用,跟之前的字符串指向同一地址的字符串對(duì)象。
以一張圖來(lái)總結(jié) String 字符串的創(chuàng)建分配內(nèi)存地址情況:
使用 intern 方法需要注意的一點(diǎn)是,一定要結(jié)合實(shí)際場(chǎng)景。因?yàn)槌A砍氐膶?shí)現(xiàn)是類(lèi)似于一個(gè) HashTable 的實(shí)現(xiàn)方式,HashTable 存儲(chǔ)的數(shù)據(jù)越大,遍歷的時(shí)間復(fù)雜度就會(huì)增加。如果數(shù)據(jù)過(guò)大,會(huì)增加整個(gè)字符串常量池的負(fù)擔(dān)。
判斷字符串是否相等
//?運(yùn)行環(huán)境?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
//?運(yùn)行環(huán)境?JDK1.8String?s1?=?new?String("1")?+?new?String("1");s1.intern();String?s2?=?"11";System.out.println(s1?==?s2);?//?true?,?如果不執(zhí)行1.intern(),則返回false
String s1 = new String("1") + new String("1")
會(huì)在堆中組合一個(gè)新的字符串對(duì)象"11"
,在s1.intern()
之后,由于常量池中沒(méi)有該字符串的引用,所以常量池中生成一個(gè)堆中字符串"11"
的引用,此時(shí)String s2 = "11"
返回的是堆字符串"11"
的引用,所以s1==s2
。
在JDK1.7版本以及之后的版本運(yùn)行以下代碼,你會(huì)發(fā)現(xiàn)結(jié)果為true,在JDK1.6版本運(yùn)行的結(jié)果卻為false:
String?s1?=?new?String("1")?+?new?String("1");System.out.println(?s1.intern()==s1);
StringBuilder與StringBuffer
由于String的值是不可變的,這就導(dǎo)致每次對(duì)String的操作都會(huì)生成新的String對(duì)象,這樣不僅效率低下,而且大量浪費(fèi)有限的內(nèi)存空間。
和 String 類(lèi)不同的是,StringBuffer 和 StringBuilder 類(lèi)的對(duì)象能夠被多次的修改,并且不產(chǎn)生新的對(duì)象。
StringBuilder 類(lèi)在 Java 5 中被提出,它和 StringBuffer 之間的最大不同在于 StringBuilder 的方法不是線程安全的(不能同步訪問(wèn))。
由于 StringBuilder 相較于 StringBuffer 有速度優(yōu)勢(shì),所以多數(shù)情況下建議使用 StringBuilder 類(lèi)。然而在應(yīng)用程序要求線程安全的情況下,則必須使用 StringBuffer 類(lèi)。
The above is the detailed content of Insight String string. For more information, please follow other related articles on the PHP Chinese website!

Hot AI Tools

Undress AI Tool
Undress images for free

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)