답변:
변이성 차이 :
String
이다 불변 당신이 그 값을 변경하려고하면, 또 다른 목적은 반면, 작성되는, StringBuffer
그리고 StringBuilder
있습니다 가변 그들의 값을 변경할 수 있습니다.
스레드 안전성 차이 :
의 차이 StringBuffer
와는 StringBuilder
즉 StringBuffer
스레드 안전합니다. 따라서 응용 프로그램을 단일 스레드에서만 실행해야하는 경우 사용하는 것이 좋습니다 StringBuilder
. StringBuilder
보다 효율적 StringBuffer
입니다.
상황 :
String
객체는 변경할 수 없으므로 String 클래스를 사용하십시오 .StringBuilder
것으로 충분합니다.StringBuffer
때문에를 사용하십시오 StringBuffer
.Strings
값을 변경하면 다른 객체가 만들어집니다. 이전 객체 참조가 무효화되어 가비지 수집 GC
되거나 가비지 수집됩니까?
String
에 StringBuilder
?
String
불변의 구조가 적합한 경우; 에서 새로운 문자 시퀀스를 얻는 것은 String
CPU 시간 또는 메모리에서 허용 할 수없는 성능 저하를 가져올 수 있습니다 (데이터가 복사되지 않기 때문에 서브 스트링을 얻는 것이 CPU 효율적이지만, 이는 잠재적으로 훨씬 많은 양의 데이터가 할당 된 상태로 남아있을 수 있음).StringBuilder
일반적으로 여러 문자 시퀀스를 연결하기 위해 가변 문자 시퀀스를 만들어야 할 때 사용 합니다.StringBuffer
당신이 사용하는 것과 같은 상황에서 StringBuilder
, 그러나 기본 문자열로 변경하는 경우 (여러 개의 스레드가 읽기 때문에 / modifyind 문자열 버퍼)를 동기화해야합니다.기본 사항 :
String
불변의 클래스이므로 변경할 수 없습니다.
StringBuilder
, 추가 문자를 교체하거나 제거하고 궁극적으로 변환 할 수있는 가변 클래스는 String
StringBuffer
원래 동기화 버전StringBuilder
StringBuilder
객체에 액세스하는 단일 스레드 만있는 모든 경우를 선호해야 합니다.
세부 사항 :
또한 StringBuilder/Buffers
마술이 아니라 배열을 백업 개체로 사용하기 때문에 배열이 가득 차면 배열을 다시 할당해야합니다. 호출 StringBuilder/Buffer
될 때마다 지속적으로 크기를 조정할 필요가없는 원래 충분히 큰 객체를 작성하십시오 .append()
.
크기 조정은 매우 저하 될 수 있습니다. 기본적으로 확장해야 할 때마다 기본 배열의 크기를 현재 크기의 2 배로 조정합니다. 이로 인해 많은 양의 RAM이 할당되고 StringBuilder/Buffer
클래스가 커지기 시작할 때 사용되지 않을 수 있습니다.
자바 String x = "A" + "B";
에서는 StringBuilder
배후를 사용 합니다. 따라서 간단한 경우에는 자신을 선언해도 이점이 없습니다. 그러나 String
4k 미만의 큰 객체를 빌드하는 경우 선언하는 StringBuilder sb = StringBuilder(4096);
것이 연결 또는 16자인 기본 생성자 를 사용하는 것보다 훨씬 효율적 입니다. 당신이 경우 String
적은 10K보다가 될 것입니다 후 안전을 위해 10K에 생성자를 초기화합니다. 그러나 10k로 초기화되면 10k보다 큰 1자를 쓰면 다시 할당되고 20k 배열로 복사됩니다. 따라서 높은 초기화는 낮은 것보다 낫습니다.
자동 크기 조정의 경우, 17 번째 문자에서 백업 배열이 재배치되어 32 자로 복사되고, 33 번째 문자에서 다시 발생하고 배열을 64 문자로 다시 할당하고 복사하게됩니다. 이 방법이 많은 재 할당 및 사본으로 어떻게 퇴보되는지 확인할 수 있습니다 StringBuilder/Buffer
.
AbstractStringBuilder의 JDK 6 소스 코드에서 가져온 것입니다.
void expandCapacity(int minimumCapacity) {
int newCapacity = (value.length + 1) * 2;
if (newCapacity < 0) {
newCapacity = Integer.MAX_VALUE;
} else if (minimumCapacity > newCapacity) {
newCapacity = minimumCapacity;
}
value = Arrays.copyOf(value, newCapacity);
}
가장 좋은 방법은 StringBuilder/Buffer
손이 얼마나 큰지 알지 String
못하지만 추측 할 수있는 경우 필요한 것보다 조금 크게 초기화하는 것 입니다. 필요한 것보다 약간 더 많은 메모리를 할당하는 것이 많은 재 할당 및 사본보다 낫습니다.
또한 String + 16 문자의 크기 만 할당 StringBuilder/Buffer
하는 String
as를 사용 하여 a 를 초기화하는 것을주의하십시오 . 대부분의 경우 피하려고하는 퇴화 재 할당 및 복사주기 만 시작합니다. 다음은 Java 6 소스 코드와 동일합니다.
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
우연히 StringBuilder/Buffer
생성하지 않았고 호출 된 생성자를 제어 할 수없는 인스턴스가 생길 경우, 재 할당 및 복사 동작의 변형을 피할 수있는 방법이 있습니다. .ensureCapacity()
결과 String
가 나아지도록 원하는 크기로 전화 하십시오 .
대안 :
참고로, 실제로 무거운 String
건물과 조작을 수행하는 경우 Ropes 라는 훨씬 성능 지향적 인 대안이 있습니다.
또 다른 대안은 StringList
서브 클래 싱을 통해 구현 을 생성하고 ArrayList<String>
카운터를 추가 .append()
하여 목록의 모든 돌연변이 작업에서 문자 수를 추적 한 다음 재정 의하여 필요한 정확한 크기 .toString()
를 생성 StringBuilder
하고 목록을 반복하여 빌드하는 것입니다. 출력을 StringBuilder
통해 인스턴스 변수를 만들고 결과를 '캐시'하고 .toString()
무언가가 변경 될 때만 다시 생성해야합니다.
또한 String.format()
고정 형식의 출력을 빌드 할 때 잊지 말고 컴파일러가 더 나은 결과를 얻을 수 있도록 최적화하십시오.
String x = "A" + "B";
실제로 StringBuilder로 컴파일 합니까 ? 그냥 컴파일하지 않는 이유는 String x = "AB";
컴파일 타임에 구성 요소를 알 수없는 경우에만 StringBuilder를 사용해야합니다.
연결을 의미합니까?
실제 예 : 많은 다른 문자열 중에서 새 문자열을 만들려고합니다 .
예를 들어 메시지를 보내려면 :
끈
String s = "Dear " + user.name + "<br>" +
" I saw your profile and got interested in you.<br>" +
" I'm " + user.age + "yrs. old too"
StringBuilder
String s = new StringBuilder().append.("Dear ").append( user.name ).append( "<br>" )
.append(" I saw your profile and got interested in you.<br>")
.append(" I'm " ).append( user.age ).append( "yrs. old too")
.toString()
또는
String s = new StringBuilder(100).appe..... etc. ...
// The difference is a size of 100 will be allocated upfront as fuzzy lollipop points out.
StringBuffer (구문은 StringBuilder와 동일하며 효과가 다릅니다)
약
StringBuffer
vs. StringBuilder
전자는 동기화되고 나중에는 동기화되지 않습니다.
따라서 단일 스레드 (경우의 90 %)에서 여러 번 호출 하면 스레드 잠금을 소유하고 있는지 확인하지 않기 때문에 훨씬 빠르게 StringBuilder
실행 됩니다.
따라서 사용하는 것이 좋습니다 StringBuilder
(물론 동시에 두 개 이상의 스레드에 액세스하지 않는 한 드문 경우입니다)
String
연결 ( + 연산자 사용 )은 StringBuilder
아래에서 사용하도록 컴파일러에 의해 최적화 될 수 있으므로 Java의 초기에는 더 이상 걱정할 것이 없습니다. 새로운 String 객체를 작성했습니다. 최신 컴파일러는 더 이상이 작업을 수행하지 않지만 StringBuilder
"오래된"컴파일러를 사용하는 경우를 대비 하여 사용하는 것이 좋습니다 .
편집하다
호기심이 많은 사람을 위해이 클래스에서 컴파일러가 수행하는 작업은 다음과 같습니다.
class StringConcatenation {
int x;
String literal = "Value is" + x;
String builder = new StringBuilder().append("Value is").append(x).toString();
}
javap -c StringConcatenation
Compiled from "StringConcatenation.java"
class StringConcatenation extends java.lang.Object{
int x;
java.lang.String literal;
java.lang.String builder;
StringConcatenation();
Code:
0: aload_0
1: invokespecial #1; //Method java/lang/Object."<init>":()V
4: aload_0
5: new #2; //class java/lang/StringBuilder
8: dup
9: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
12: ldc #4; //String Value is
14: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
17: aload_0
18: getfield #6; //Field x:I
21: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
24: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
27: putfield #9; //Field literal:Ljava/lang/String;
30: aload_0
31: new #2; //class java/lang/StringBuilder
34: dup
35: invokespecial #3; //Method java/lang/StringBuilder."<init>":()V
38: ldc #4; //String Value is
40: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
43: aload_0
44: getfield #6; //Field x:I
47: invokevirtual #7; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
50: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
53: putfield #10; //Field builder:Ljava/lang/String;
56: return
}
숫자 5-27은 "literal"이라는 문자열입니다.
번호 31-53은 "builder"라는 문자열입니다.
차이점은 없습니다 . 두 문자열에 대해 정확히 동일한 코드가 실행됩니다.
StringBuilder
과제의 오른쪽에 문자열 연결 을 사용하는 것은 좋지 않습니다 . 좋은 구현은 말 그대로 장면 뒤에서 StringBuilder를 사용합니다. 또한 예제 "a" + "b"
는 단일 리터럴로 컴파일 "ab"
되지만 사용 StringBuilder
하면에 대한 두 번의 불필요한 호출이 발생합니다 append()
.
"a"+"b"
하려고하는 것이 아니라 String 연결 이 무엇인지 명시 적으로 변경했습니다. 당신이 말하지 않는 것은 왜 그렇게하는 것이 좋은 습관이 아니라는 것입니다. 그것이 바로 현대 컴파일러가하는 일입니다. @fuzzy, 나는 최종 문자열의 크기 (aprox)가 무엇인지 알 때 특히 동의합니다.
-------------------------------------------------- -------------------------------- String StringBuffer StringBuilder -------------------------------------------------- -------------------------------- 저장 영역 | 상수 문자열 풀 힙 힙 수정 가능 | 아니오 (불변) 예 (변동 가능) 예 (변동 가능) 스레드 안전 | 예 예 아니요 성과 | 매우 빠름 -------------------------------------------------- --------------------------------
synchronised
그 이유 입니다.
끈
는 String class
문자열을 나타냅니다. Java 프로그램의 모든 문자열 리터럴 "abc"
은이 클래스의 인스턴스로 구현됩니다.
String 객체는 불변 그들은 우리가 변경할 수 없습니다 생성되면. ( 문자열은 상수입니다 )
생성자 또는 메소드를 사용하여 문자열을 작성하면 해당 문자열은 힙 메모리 에도 저장 됩니다 SringConstantPool
. 그러나 풀에 저장하기 전에 intern()
equals 메소드를 사용하여 풀의 동일한 컨텐츠로 오브젝트 가용성을 확인하는 메소드를 호출합니다 . 풀에서 문자열 복사를 사용할 수 있으면 참조를 반환합니다. 그렇지 않으면 String 객체가 풀에 추가되고 참조를 반환합니다.
+
) 및 다른 객체를 문자열로 변환 하는 데 특별한 지원을 제공합니다 . 문자열 연결은 StringBuilder (또는 StringBuffer) 클래스와 해당 append 메서드를 통해 구현됩니다.String heapSCP = new String("Yash");
heapSCP.concat(".");
heapSCP = heapSCP + "M";
heapSCP = heapSCP + 777;
// For Example: String Source Code
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
문자열 리터럴은에 저장됩니다 StringConstantPool
.
String onlyPool = "Yash";
StringBuilder 및 StringBuffer 는 변경 가능한 문자 시퀀스입니다. 즉, 이러한 객체의 값을 변경할 수 있습니다. StringBuffer는 StringBuilder와 동일한 메소드를 갖지만 StringBuffer의 각 메소드는 동기화되어 스레드로부터 안전합니다.
StringBuffer 및 StringBuilder 데이터는 new 연산자를 사용해서 만 만들 수 있습니다. 따라서 힙 메모리에 저장됩니다.
StringBuilder 인스턴스는 여러 스레드에서 사용하기에 안전하지 않습니다. 이러한 동기화가 필요한 경우 StringBuffer를 사용하는 것이 좋습니다.
StringBuffer threadSafe = new StringBuffer("Yash");
threadSafe.append(".M");
threadSafe.toString();
StringBuilder nonSync = new StringBuilder("Yash");
nonSync.append(".M");
nonSync.toString();
StringBuffer를하고 모두 StringBuilder 같은. 특별 방법을 가지고,된다
replace(int start, int end, String str)
하고 reverse()
.
참고 : StringBuffer 및 SringBuilder는 구현을 제공하므로 변경할 수
Appendable Interface
있습니다.
어느 것을 사용할 때.
매번 값을 변경하지 않으려면 사용하는 것이 좋습니다 String Class
. Comparable<T>
값 을 정렬 하거나 비교 하려면 Generics의 일부로 이동하십시오 String Class
.
//ClassCastException: java.lang.StringBuffer cannot be cast to java.lang.Comparable
Set<StringBuffer> set = new TreeSet<StringBuffer>();
set.add( threadSafe );
System.out.println("Set : "+ set);
매번 값을 수정하려면 StringBuffer보다 빠른 StringBuilder를 사용하십시오. 여러 스레드가 값을 수정하는 경우 StringBuffer로 이동하십시오.
Java 5 이상을 사용 StringBuilder
하는 경우 대신을 사용해야 합니다 StringBuffer
. API 설명서에서 :
릴리스 JDK 5부터이 클래스에는 단일 스레드에서 사용하도록 설계된 동등한 클래스가 추가되었습니다
StringBuilder
.StringBuilder
는 동일한 동작을 모두 지원하지만 아무런 동기화를 수행하지 않기 때문에 그것이 빠르기 때문 클래스는 일반적으로,이 우선적으로 사용되어야한다.
실제로는 여러 스레드에서 동시에 StringBuffer
거의 사용하지 않으므로 동기화 는 거의 항상 불필요한 오버 헤드입니다.
개인적으로에 대한 실제 사용은 없다고 생각합니다 StringBuffer
. 문자 시퀀스를 조작하여 여러 스레드간에 통신하고 싶은 경우는 언제입니까? 그것은 전혀 유용하게 들리지 않지만 어쩌면 나는 아직 빛을 보지 못했을 것입니다 :)
String과 다른 두 클래스의 차이점은 String은 변경 불가능하고 다른 두 클래스는 변경 가능 클래스라는 것입니다.
그런데 왜 같은 목적으로 두 개의 수업이 있습니까?
그 이유는 StringBuffer
스레드 안전이며 StringBuilder
그렇지 않습니다.
StringBuilder
새로운 클래스 StringBuffer Api
이며 소개되었으며 JDK5
항상 단일 스레드 환경에서 작업하는 경우 권장됩니다.Faster
자바에서 문자열 은 변경할 수 없습니다. 변경할 수 없다는 것은 일단 문자열이 생성되면 값을 변경할 수 없음을 의미합니다. StringBuffer 는 변경 가능합니다. StringBuffer 객체가 만들어지면 새 객체를 만드는 대신 내용을 객체의 값에 추가하기 만하면됩니다. StringBuilder 는 StringBuffer 와 비슷하지만 스레드로부터 안전하지 않습니다. StingBuilder의 메소드는 동기화되지 않지만 다른 문자열과 비교하여 Stringbuilder가 가장 빠르게 실행됩니다. String, StringBuilder 및 StringBuffer 를 구현하여 차이점을 배울 수 있습니다 .