String과 StringBuffer의 차이점은 모두가 잘 알고 있다고 생각합니다. 하지만 이 두 클래스의 작동 원리에 대해서는 아직 명확하지 않은 동지가 많은 것으로 추정됩니다. 오늘은 이 개념을 모든 사람을 위해 검토해 보겠습니다. J2SE 5.0에는 StringBuilder라는 새로운 문자 연산 클래스가 도입되었습니다. 그렇다면 이 StringBuilder와 StringBuffer 그리고 우리가 처음 만난 String 클래스의 차이점은 무엇입니까? 다양한 상황에서 어느 것을 사용해야 할까요? 나는 이러한 범주들에 대해 나의 견해를 공유하고 싶고, 또한 모두가 자신의 의견을 제시할 수 있기를 바랍니다.
간단히 말해서 String 유형과 StringBuffer 유형의 주요 성능 차이는 실제로 String이 불변 객체라는 것입니다. (왜? Java 설계자에게 String이 왜 기본 유형이 아닌지 물어보십시오.) 따라서 String 유형이 변경될 때마다 , 실제로는 새 String 객체를 생성한 다음 새 String 객체에 대한 포인터를 가리키는 것과 같습니다. 따라서 객체가 생성될 때마다 내용이 자주 변경되는 문자열에는 String을 사용하지 않는 것이 가장 좋습니다. 특히 메모리를 사용할 때 참조되지 않는 객체가 너무 많으면 JVM의 GC가 작동하기 시작하고 속도가 상당히 느려집니다. 다음은 그다지 적절하지 않은 예입니다.
이 경우 for 루프가 완료된 후 GC에 의해 메모리에 있는 객체가 지워지지 않았다면 메모리에 20,000개가 넘는 놀라운 숫자가 있을 것이며, 이것이 많은 사람들이 사용하는 시스템이라면 그렇다면 숫자가 그리 많지 않으니 다들 조심해서 사용하셔야 합니다.
StringBuffer 클래스를 사용하는 경우 결과는 매번 달라지며, 새 개체를 생성한 다음 개체 참조를 변경하는 대신 StringBuffer 개체 자체에 대한 작업이 됩니다. 따라서 일반적으로 특히 문자열 개체가 자주 변경되는 경우에는 StringBuffer를 사용하는 것이 좋습니다. 일부 특수한 경우에는 String 객체의 문자열 연결이 실제로 JVM에 의해 StringBuffer 객체의 연결로 해석되므로 이러한 경우 String 객체의 속도는 StringBuffer 객체의 속도보다 느리지 않으며 특히 다음 문자열 객체는 다음과 같습니다. 그 중에서 String 효율성은 StringBuffer보다 훨씬 빠릅니다.
String S1 객체를 생성하는 속도가 너무 빠르며 현재 StringBuffer는 속도 면에서 전혀 이점이 없다는 사실에 놀랄 것입니다. 실제로 이것은 JVM의 트릭입니다.
이것으로부터 우리는 첫 번째 단계 결론을 얻습니다: 대부분의 경우 StringBuffer > String
그리고 StringBuilder는 이들과 어떻게 비교됩니까? 먼저 간단히 소개하자면, StringBuilder는 JDK5.0에 새로 추가된 클래스이며, StringBuffer와의 차이점은 다음과 같습니다(출처: JavaWorld).
Java.lang.StringBuffer 스레드로부터 안전한 변경 가능 문자 시퀀스입니다. String과 유사하지만 수정할 수 없는 문자열 버퍼입니다. 문자열 버퍼는 여러 스레드에서 안전하게 사용할 수 있습니다. 필요한 경우 이러한 메서드를 동기화할 수 있으므로 특정 인스턴스의 모든 작업이 관련된 각 스레드의 메서드 호출 순서와 일치하는 직렬 순서로 발생하는 것처럼 보입니다.
각 문자열 버퍼에는 특정 용량이 있습니다. 문자열 버퍼에 포함된 문자 시퀀스의 길이가 이 용량을 초과하지 않는 한 새 내부 버퍼 배열을 할당할 필요는 없습니다. 내부 버퍼가 오버플로되면 이 용량이 자동으로 늘어납니다. JDK 5.0부터는 단일 스레드 사용에 해당하는 클래스인 StringBuilder가 이 클래스에 추가되었습니다. StringBuilder 클래스는 동일한 작업을 모두 지원하지만 동기화를 수행하지 않기 때문에 더 빠르기 때문에 일반적으로 이 클래스보다 우선적으로 사용되어야 합니다.
그러나 여러 스레드가 있는 StringBuilder 인스턴스를 사용하는 것은 안전하지 않습니다. 이러한 동기화가 필요한 경우 StringBuffer를 사용하는 것이 좋습니다.
이렇게 말하면 모든 사람이 둘 사이의 차이점을 이해할 수 있다고 생각하므로 아래에서 일반적인 파생을 만들어 보겠습니다.
대부분의 경우 StringBuilder > StringBuffer
따라서 이 부등식의 전이 정리에 따르면 대부분의 경우 StringBuilder > StringBuffer > String입니다.
이제 이러한 파생 결과가 나왔으므로 테스트를 통해 확인해 보겠습니다.
테스트 코드는 다음과 같습니다.
/** testsb의 새 인스턴스를 생성합니다 */
final static int ttime = 10000;//테스트 루프 수
공개 테스트sb() {
}
공개 무효 테스트(문자열 s){
긴 시작 = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s += "추가";
}
오랫동안 = System.currentTimeMillis();
System.out.println(""+s.getClass().getName()+" 작업 유형에 사용된 시간은 다음과 같습니다. " + (over - start) + " 밀리초" );
}
공개 무효 테스트(StringBuffer s){
긴 시작 = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s.append("추가");
}
오랫동안 = System.currentTimeMillis();
System.out.println(""+s.getClass().getName()+" 작업 유형에 사용된 시간은 다음과 같습니다. " + (over - start) + " 밀리초" );
}
공개 무효 테스트(StringBuilder s){
긴 시작 = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
s.append("추가");
}
오랫동안 = System.currentTimeMillis();
System.out.println(""+s.getClass().getName()+" 작업 유형에 사용된 시간은 다음과 같습니다. " + (over - start) + " 밀리초" );
}
// String에서 문자열 연결을 직접 테스트합니다.
공개 무효 테스트2(){
문자열 s2 = "abadf";
긴 시작 = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
문자열 s = s2 + s2 + s2 ;
}
오랫동안 = System.currentTimeMillis();
System.out.println("문자열 객체 참조 추가 유형을 연산하는 데 사용되는 시간은 다음과 같습니다: " + (over - start) + " 밀리초" );
}
공개 무효 test3(){
긴 시작 = System.currentTimeMillis();
for(int i=0;i<ttime;i++){
문자열 s = "abadf" + "abadf" + "abadf" ;
}
오랫동안 = System.currentTimeMillis();
System.out.println("작업 문자열을 추가하는 데 사용되는 시간은 다음과 같습니다. "+ (over - start) + " 밀리초" );
}
공개 정적 무효 메인(문자열[] 인수){
문자열 s1="abc";
StringBuffer sb1 = new StringBuffer("abc");
StringBuilder sb2 = new StringBuilder("abc");
테스트sb t = 새로운 테스트sb();
t.test(s1);
t.test(sb1);
t.test(sb2);
t.test2();
t.test3();
}
}
StringBuffer와 StringBuilder의 차이점을 여전히 볼 수 없는 것 같습니다. ttime을 30000번 추가하고 다음을 확인하세요.
java.lang.String 유형을 작동하는 데 사용된 시간: 53444밀리초 java.lang.StringBuffer 유형을 작동하는 데 사용된 시간: 15밀리초 java.lang.StringBuilder 유형을 작동하는 데 사용된 시간: 15밀리초 시간 문자열 객체 참조 추가 유형을 연산하는 데 사용됨 소요 시간: 31밀리초 문자열 추가에 소요된 시간: 0밀리초
StringBuffer와 StringBuilder의 성능에는 여전히 큰 차이가 없습니다. 이를 100000으로 늘리고 살펴보겠습니다. String 유형에 대한 테스트는 너무 많기 때문에 여기에 추가하지 않겠습니다. 매우 느리다...
java.lang.StringBuffer 유형을 작동하는 데 걸린 시간은: 31밀리초입니다. java.lang.StringBuilder 유형을 작동하는 데 걸린 시간은: 16밀리초입니다.
차이점을 볼 수 있지만 많은 테스트 결과에서는 StringBuffer가 StringBuilder보다 빠르다는 것을 보여줍니다. 값을 1000000으로 늘리고 살펴보겠습니다(충돌하지 않아야 합니다. 그렇죠?).
java.lang.StringBuffer 유형을 작동하는 데 걸린 시간은: 265밀리초입니다. java.lang.StringBuilder 유형을 작동하는 데 걸린 시간은: 219밀리초입니다.
차이가 적고 결과가 매우 안정적입니다. 조금 더 크게 ttime = 5000000으로 살펴보겠습니다.
・・・・・・ 스레드 "main"의 예외 java.lang.OutOfMemoryError: Java 힙 공간 ・・・・・・
하하, 더 이상 테스트하지 않겠습니다. 기본적으로 성능은 StringBuilder > StringBuffer > String 입니다.