집 >백엔드 개발 >C#.Net 튜토리얼 >String StringBuffer StringBuilder 도구
문자열 문자열 상수
StringBuffer 문자열 변수(스레드 안전)
StringBuilder 문자열 변수(스레드 안전 아님)
간단히 말하면 String 유형과 StringBuffer 유형의 주요 성능 차이는 String이 불변 객체이므로 String 유형이 변경될 때마다 실제로는 새 String 객체를 생성한 다음 새 String 객체에 대한 포인터를 가리키는 것과 같습니다. 따라서 내용이 자주 변경되는 문자열에는 String을 사용하지 않는 것이 가장 좋습니다. 왜냐하면 객체가 생성될 때마다 시스템 성능에 영향을 미치기 때문입니다. 특히 메모리에 참조되지 않은 객체가 너무 많으면 JVM의 GC가 작동하기 시작하고 속도가 상당히 느려질 것입니다.
StringBuffer 클래스를 사용하면 결과가 달라집니다. 각 결과는 새 개체를 생성한 다음 개체 참조를 변경하는 대신 StringBuffer 개체 자체에서 작동합니다. 따라서 일반적으로 특히 문자열 개체가 자주 변경되는 경우에는 StringBuffer를 사용하는 것이 좋습니다. 일부 특수한 경우에는 String 객체의 문자열 연결이 실제로 JVM에 의해 StringBuffer 객체의 연결로 해석되므로 이러한 경우 String 객체의 속도는 StringBuffer 객체의 속도보다 느리지 않으며 특히 다음 문자열 객체는 다음과 같습니다. 생성된 중에서 String 효율성은 StringBuffer보다 훨씬 빠릅니다.
String S1 = “This is only a” + “simple” + “test”
StringBuffer Sb = new StringBuilder(“This is only a”). append("simple").append("test");
String S1 객체 생성 속도가 너무 빠르다는 사실에 놀랄 것입니다. 현재 StringBuffer는 실제로 속도 면에서 전혀 이점이 없습니다. 실제로 이는 JVM의 트릭입니다.
String S1 = “This is only a” + “simple” + “test”입니다.
String S1 = “ 이것은 단순한 테스트일 뿐이므로 당연히 시간이 많이 걸리지 않습니다. 그러나 여기서 모두가 주목해야 할 점은 문자열이 다른 String 객체에서 온 경우 속도가 그다지 빠르지 않다는 것입니다. 예를 들어:
String S2 = “This is only a”
String S3 = “ simple”; ;
String S4 = “test”;
String S1 = S2 +S3 + S4
이때 JVM은
일반적으로 StringBuffer > String
StringBuffer
Java.lang.StringBuffer 스레드로부터 안전한 변경 가능 문자 시퀀스입니다. String과 유사하지만 수정할 수 없는 문자열 버퍼입니다. 특정 시점의 특정 문자 시퀀스가 포함되어 있더라도 해당 시퀀스의 길이와 내용은 특정 메서드 호출을 통해 변경될 수 있습니다.
문자열 버퍼는 여러 스레드에서 안전하게 사용할 수 있습니다. 필요한 경우 이러한 메서드를 동기화할 수 있으므로 특정 인스턴스의 모든 작업이 관련된 각 스레드의 메서드 호출 순서와 일치하는 직렬 순서로 발생하는 것처럼 보입니다.
StringBuffer의 주요 작업은 모든 유형의 데이터를 허용하도록 오버로드될 수 있는 추가 및 삽입 메서드입니다. 각 메서드는 주어진 데이터를 문자열로 효과적으로 변환한 다음 해당 문자열의 문자를 문자열 버퍼에 추가하거나 삽입합니다. 추가 방법은 항상 이러한 문자를 버퍼의 끝에 추가합니다. 삽입 방법은 지정된 지점에 문자를 추가합니다.
예를 들어, z가 현재 내용이 "start"인 문자열 버퍼 개체를 참조하는 경우 이 메서드 호출 z.append("le")는 문자열 버퍼에 "startle"을 포함하게 하고 z.insert( 4, "le")은 "starlet"을 포함하도록 문자열 버퍼를 변경합니다.
대부분의 경우 StringBuilder > StringBuffer
java.lang.StringBuilde
java.lang.StringBuilder 가변 문자 시퀀스는 5.0의 새로운 기능입니다. 이 클래스는 StringBuffer 호환 API를 제공하지만 동기화를 보장하지는 않습니다. 이 클래스는 문자열 버퍼가 단일 스레드에서 사용될 때(일반적인 상황) StringBuffer에 대한 드롭인 대체품으로 설계되었습니다. 대부분의 구현에서 StringBuffer보다 빠르므로 가능하면 이 클래스를 선호하는 것이 좋습니다. 두 방법 모두 기본적으로 동일합니다.
============================================= === =========================
String 클래스에 대한 자세한 설명
1. String 클래스는 최종 클래스이므로 상속할 수 없습니다. .
2. String 클래스의 핵심은 문자 배열 char[]이며, 그 값은 변경할 수 없습니다. PRivate final char value[];
그런 다음 String 클래스의 API 문서를 열면 다음을 찾을 수 있습니다.
3. String 클래스 객체에는 String x를 직접 지정하는 특별한 방법이 있습니다. = "abc", "abc "는 문자열 객체를 의미합니다. 그리고 x는 "abc" 개체에 대한 참조로
이라고도 하는 "abc" 개체의 주소입니다.
4. 문자열 객체는 "+"를 통해 연결할 수 있습니다. 연결 후에는 새 문자열이 생성됩니다. 나중에 설명할 concat()을 통해 연결할 수도 있습니다.
6. Java는 실행 시 문자열 풀을 유지합니다. JavaDoc 번역은 "문자열 버퍼"로 매우 모호합니다. 문자열 풀은 런타임 중에 생성된 다양한 문자열을 저장하는 데 사용됩니다.
그리고 풀에 있는 문자열의 내용은 반복되지 않습니다. 이 버퍼 풀은 일반 객체에는 존재하지 않으며, 생성된 객체는 메소드의 스택 영역에만 존재합니다.
5. 문자열을 생성하는 방법은 다양하며 세 가지 범주로 요약할 수 있습니다.
먼저 new 키워드를 사용하여 String s1 = new String(" abc");
둘째, 직접 지정합니다. 예를 들어 String s2 = "abc";
셋째, 연결을 사용하여 새 문자열을 생성합니다. 예를 들어 String s3 = "ab" + "c";
2. String 객체 생성
String 객체 생성도 매우 까다롭습니다.
원리 1: 문자열 개체를 생성하기 위해 어떤 메서드를 사용하든 Java 런타임(JVM 실행)은 이 X를 사용하여 문자열 풀에 동일한 내용을 가진 문자열 개체가 있는지 확인합니다.
존재하지 않으면 풀에 문자열 s를 생성하고, 그렇지 않으면 풀에 추가하지 마십시오.
원칙 2: Java에서는 new 키워드를 사용하여 객체를 생성하는 한 반드시 새 객체가 생성됩니다(힙 또는 스택 영역에).
원칙 3: 직접 지정을 사용하거나 순수 문자열 연결을 사용하여 String 객체를 생성하면 String 풀에 있는 문자열만 확인하고 유지됩니다. 풀에 문자열이 없으면 수영장, 그렇지 않으면
알겠습니다! 그러나 String 개체는 스택 영역에 생성되지 않습니다.
원리 4: 변수가 포함된 표현식을 사용하여 String 객체를 생성하면 String pool을 확인하고 유지할 뿐만 아니라 스택 영역에 String 객체도 생성됩니다.
또한 String의 intern() 메소드는 public Native String intern()으로 정의된 로컬 메소드로, 개발자가
스트링 풀. 인턴 메서드가 호출될 때 풀에 이미 이 String 객체와 동일한 문자열이 포함되어 있으면(equals(Object) 메서드에 의해 결정됨) 풀의
문자열이 반환됩니다. 그렇지 않으면 이 String 개체가 풀에 추가되고 이 String 개체에 대한 참조가 반환됩니다.
3. 불변 클래스
불변 문자열은 큰 장점이 있습니다. 컴파일러는 문자열을 공유하도록 설정할 수 있습니다.
불변 문자열 클래스는 공유 참조가 아니라는 중요한 이점을 가지고 있습니다.
효율성을 높이기 위해 JAVA는 문자열 유형에 대한 문자열 풀을 제공하는 특수 처리를 수행했습니다.
문자열 유형 변수를 정의하는 방법에는 두 가지가 있습니다. >string name= "tom ";
string name =new string( "tom ")
첫 번째 방법을 사용할 때는 string pool을 사용합니다.
두 번째 방법을 사용할 때는 일반적인 방법입니다. 객체 선언
첫 번째 방법을 사용하면 내용이 "tom"인 문자열을 선언하면 메모리를 다시 생성하지 않고 문자열 풀의 원래 메모리, 즉 문자열을 사용합니다. saname = "tom "은 동일한 메모리를 가리킵니다
또한 문자열 유형이 불변인 문제에 대해:
문자열 유형이 불변입니다. 즉, 문자열을 변경하려는 경우 name = "madding "
과 같은 개체를 사용하면 가상 머신은 원래 개체를 변경하지 않고 새 문자열 개체를 생성한 다음 이름이 해당 개체를 가리키도록 합니다. " tom " 개체가 없습니다. 이를 참조하면 가상 머신의 가비지 수집 메커니즘이 이를 수신합니다.
이렇게 하면 효율성이 향상된다고 하네요! ! !
============================================= === =========================final StringBuffer a = new StringBuffer("111")
final StringBuffer b = new StringBuffer ("222 ");
a=b;//이 문장은 컴파일을 통과하지 못했습니다.
final StringBuffer a = new StringBuffer("111")
a.append("222");/ /컴파일이 통과됩니다.
최종은 참조의 "값"(즉, 메모리 주소)에 대해서만 유효하다는 것을 알 수 있습니다. 참조가 처음에 가리키는 개체만 가리키도록 강제합니다. 컴파일 타임 오류가 발생합니다. 그것이 가리키는 객체의 변경에 대해서는 final이 책임을 지지 않습니다.
문자열 상수 풀 문제의 네 가지 예
다음은 몇 가지 일반적인 예를 비교 분석하고 이해한 것입니다.
[1]
String a = "a1"; >String b = "a" + 1;
System.out.println((a == b)); //result = true
String a = "atrue"
String b = "a " + "true";
System.out.println((a == b)); //result = true
String a = "a3.4";
String b = "a" + 3.4;
System.out.println((a == b)); //결과 = true
분석: JVM은 프로그램 컴파일 중에 문자열 상수의 "+" 연결을 연결 후의 값으로 최적화합니다. 예를 들어 컴파일러 최적화 후 "a" + 1을 사용하면 클래스에 이미 a1이 있습니다. 문자열 상수의 값은 컴파일 중에 결정되므로 위 프로그램의 최종 결과는 true입니다.
[2]
String a = "ab";
String bb = "b"
String b = "a" + bb
System.out.println( (a == b)); //result = false
분석: 문자열 참조의 경우 JVM은 문자열의 "+" 연결에 문자열 참조가 있으며 참조 값은 프로그램 컴파일 중에 있습니다. 즉, "a" + bb는 컴파일러에 의해 최적화될 수 없습니다. 이는 프로그램 실행 중에만 동적으로 할당될 수 있으며 b에 연결한 후에 새 주소를 할당할 수 있습니다. 따라서 위 프로그램의 결과는 거짓입니다.
[3]
문자열 a = "ab";
최종 문자열 bb = "b"
문자열 b = "a" + bb
System.out.println ((a == b)); //result = true
분석: [3]과의 유일한 차이점은 bb 문자열이 최종 수정된 변수의 경우 컴파일 타임 A에서 상수로 구문 분석된다는 것입니다. 값의 로컬 복사본은 자체 상수 풀에 저장되거나 바이트코드 스트림에 포함됩니다.
그러니까 이때 "a" + bb와 "a" + "b"의 효과는 같습니다. 그러므로 위 프로그램의 결과는 참이다.
[4]
String a = "ab";
final String bb = getBB()
String b = "a" + bb
System.out.println; ((a == b)); //result = false
private static String getBB() { return "b" }
분석: JVM에는 문자열 참조 bb가 있으며 해당 값은 컴파일 시 확인할 수 없습니다. time , 프로그램 실행 중에 메소드가 호출된 후에만 메소드의 반환 값이 "a"에 동적으로 연결되고 주소가 b에 할당되므로 위 프로그램의 결과는 false입니다.
위의 4가지 예에서 결론을 내릴 수 있습니다.
String s = "a" + "b" + "c"; 이는 String s = "abc"와 동일합니다. >
String a = "a";
String b = "b";
String c = "c"
String s = a + b + c; , 최종 결과는 다음과 같습니다.
StringBuffer temp = new StringBuffer()
temp.append(a).append(b).append(c)
String s = temp. toString ();
위 분석 결과에서 String이 연결 연산자(+)를 사용하여 비효율적인 이유를 분석한 것을 유추하기 어렵지 않습니다.
public class Test. {
public static void main(String args[]) {
String s = null
for(int i = 0; i < 100; i++) { s += "a" }
}
}
+를 수행할 때마다 StringBuilder 개체가 생성된 다음 추가 후 폐기됩니다. 다음에 루프가 도착하면 StringBuilder 개체가 다시 생성된 다음 문자열이 추가되고 이 루프는 끝까지 계속됩니다. 추가를 위해 StringBuilder 객체를 직접 사용하면 객체 생성 및 소멸 시간을 N - 1 번 절약할 수 있습니다. 따라서 루프에서 문자열 연결이 필요한 애플리케이션의 경우 일반적으로 추가 작업에 StringBuffer 또는 StringBulider 개체가 사용됩니다.
String 객체의 인턴 메소드 이해 및 분석
public class Test4 {
private static String a = "ab"
public static void main(String[] args){
String s1 = "a";
String s2 = "b";
String s = s1 + s2
System.out.println(s == a);//false
시스템 . out.println(s.intern() == a);//true
}
}
여기서 Java를 사용하는 것은 상수 풀 문제입니다. s1+s2 작업의 경우 실제로 힙에 새 개체가 생성됩니다. s는 이 새 개체의 내용을 힙 공간에 저장하므로 s와 a의 값은 동일하지 않습니다. s.intern() 메소드를 호출하면 상수 풀에 있는 s의 주소 값이 반환될 수 있다. 상수 풀에는 a의 값이 저장되어 있기 때문에 s.intern과 a의 값은 같다.