Java Java베이스 통찰력 문자열 문자열

통찰력 문자열 문자열

Dec 28, 2020 pm 05:27 PM

java 기본 튜토리얼열은 문자열 문자열에 대한 통찰력을 소개합니다

통찰력 문자열 문자열

권장(무료): java 기본 튜토리얼

구현 원칙

Java6 및 이전 버전 이 버전에서 String 개체는 char 배열을 캡슐화하는 개체입니다. 여기에는 주로 char 배열, 오프셋 오프셋, 문자 수 및 해시 값 해시의 네 가지 멤버 변수가 있습니다.

Java7에서 Java8까지는 String 클래스에 더 이상 오프셋 및 개수 변수가 없습니다. 이것의 장점은 String 객체가 약간 적은 메모리를 차지한다는 것입니다.

Java 9 버전부터 char[] 필드가 byte[] 필드로 변경되었으며, 인코딩 형식의 식별자인 새로운 속성 코더가 유지되었습니다.

char 문자는 16비트와 2바이트를 차지합니다. 이 경우 단일 바이트 인코딩(1바이트를 차지하는 문자)으로 문자를 저장하는 것은 매우 낭비입니다. JDK1.9의 String 클래스는 메모리 공간을 절약하기 위해 8비트, 1바이트 바이트 배열을 사용하여 문자열을 저장합니다.

새 속성 코더의 기능은 문자열 길이를 계산하거나 indexOf() 함수를 사용할 때 이 필드를 기반으로 문자열 길이를 계산하는 방법을 결정해야 한다는 것입니다. coder 속성에는 기본적으로 0과 1의 두 가지 값이 있습니다. 0은 Latin-1(단일 바이트 인코딩)을 나타내고 1은 UTF-16을 나타냅니다. String에서 문자열에 Latin-1만 포함되어 있다고 판단하면 코더 속성 값은 0이고, 그렇지 않으면 1입니다.

Immutable

String 클래스의 코드를 보면 final 키워드에 의해 String 클래스가 수정되어 이 클래스를 상속할 수 없는 것을 알 수 있으며, String 클래스의 변수 char 배열도 final에 의해 수정되었으므로 String 객체를 수정할 수 없습니다.

String 개체는 변경할 수 없으며 다음과 같은 주요 장점이 있습니다.

먼저 String 개체의 보안을 보장합니다. String 개체가 변경 가능하다고 가정하면 String 개체가 악의적으로 수정될 수 있습니다.

둘째, 해시 속성 값이 자주 변경되지 않도록 하여 고유성을 보장하므로 HashMap과 유사한 컨테이너가 해당 키-값 캐시 기능을 구현할 수 있습니다.

셋째, 문자열 상수 풀을 구현할 수 있습니다.

Java에서는 일반적으로 문자열 객체를 생성하는 두 가지 방법이 있습니다.

첫 번째는 String str = "abc"와 같은 문자열 상수를 통해 생성하는 것입니다. String str = "abc"

第二种是字符串变量通过new 形式的创建,如 String str = new String("abc")

当代码中使用第一种方式创建字符串对象时,在编译类文件时,”abc”常量字符串将会放入到常量结构中,在类加载时,“abc”将会在常量池中创建;然后,str将引用常量池中的字符串对象。这种方式可以减少同一个值的字符串对象的重复创建,节约内存。

String str = new String("abc") 这种方式,首先在编译类文件时,”abc”常量字符串将会放入到常量结构中,在类加载时,“abc”将会在常量池中创建;其次,在调用new时,JVM 命令将会调用 String 的构造函数,String 对象中的 char 数组将会引用常量池中”abc”字符串的char 数组,在堆内存中创建一个 String 对象;最后,str 将引用 String 对象,String对象的引用跟常量池中”abc”字符串的引用是不一样的。

对象与引用:对象的内容存储在内存中,操作系统通过内存地址来找到存储的内容,引用就是指内存的地址。

比如:String str = new String("abc"),变量str指向的是String对象的存储地址,也就是说 str 并不是对象,而只是一个对象引用。

字符串拼接

常量相加

String str = "ab" + "cd" + "ef";
로그인 후 복사

查看编译后的字节码

0 ldc #2 <abcdef>2 astore_13 return
로그인 후 복사

可以发现编译器将代码优化成如下所示

String str= "abcdef";
로그인 후 복사

变量相加

String a = "ab";String b = "cd";String c = a + b;
로그인 후 복사

查看编译后的字节码

 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
로그인 후 복사

可以发现,Java在进行字符串相加的时候,底层使用的是StringBuilder,代码被优化成如下所示:

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);
로그인 후 복사

输出结果:

true
로그인 후 복사

在字符串常量中,默认会将对象放入常量池。例如:String a = "123"

두 번째는 String str = new String("abc")와 같이 new 형식의 문자열 변수를 만드는 것입니다. 🎜🎜첫 번째 방법을 사용하여 코드에서 문자열 객체를 생성하면 클래스 파일을 컴파일할 때 "abc" 상수 문자열이 클래스가 로드되면 "abc"가 상수 구조에 들어갑니다. 상수 풀은 다음에서 생성됩니다. 그런 다음 str은 상수 풀의 문자열 개체를 참조합니다. 이 방법을 사용하면 동일한 값을 가진 문자열 개체의 반복 생성을 줄이고 메모리를 절약할 수 있습니다. 🎜🎜String str = new String("abc") 이렇게 하면 먼저 클래스 파일을 컴파일할 때 클래스가 로드될 때 "abc" 상수 문자열이 상수 구조에 삽입됩니다. "abc"는 상수 풀에 생성됩니다. 두 번째로 new를 호출할 때 JVM 명령은 String의 생성자를 호출하고 String 객체의 char 배열은 상수 풀에 있는 문자열 "abc"의 char 배열을 참조합니다. 🎜 힙 메모리에 String 개체를 만듭니다. 마지막으로 str은 String 개체를 참조하고 String 개체의 참조는 상수 풀의 "abc" 문자열 참조와 다릅니다. 🎜🎜객체 및 참조: 객체의 내용은 메모리에 저장됩니다. 운영 체제는 메모리 주소를 통해 저장된 내용을 찾습니다. 🎜🎜예: String str = new String("abc"), 변수 str은 String 개체의 저장 주소를 가리킵니다. 즉, str은 개체가 아니라 개체 참조일 뿐입니다. . 🎜🎜🎜🎜🎜문자열 연결🎜🎜🎜🎜🎜🎜상시 추가🎜🎜
// 运行环境 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");System.out.println( s1.intern()==s1);
로그인 후 복사
로그인 후 복사
🎜 컴파일된 바이트코드를 보려면 🎜rrreee🎜 Java가 문자열을 추가할 때 맨 아래 레이어가 StringBuilder를 사용하고 코드가 다음과 같이 최적화되는 것을 확인할 수 있습니다. 🎜rrreee🎜🎜🎜🎜String.intern🎜🎜rrreee🎜출력 결과:🎜 rrreee🎜string🎜constant🎜에서 객체는 기본적으로 상수 풀에 저장됩니다. 예: 문자열 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 类。

위 내용은 통찰력 문자열 문자열의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌
Will R.E.P.O. 크로스 플레이가 있습니까?
1 몇 달 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)