최근 일자리를 찾고 있었는데 시험관이 "StringBuffer와 StringBuilder의 차이점은 무엇이며 적용 시나리오는 무엇입니까?"라는 간단한 질문을 했습니다. 편집자의 답변은 아래의 모든 사람과 공유됩니다. 누구나 미래에 배울 수 있고, 좋은 모범이 될 수도 있습니다.
실제로 Google을 검색하면 답을 얻을 수 있습니다. StringBuffer와 StringBuilder의 메서드와 함수는 완전히 동일하지만 StringBuffer의 대부분의 메서드는 동기화된 키워드로 수정되므로 스레드입니다. safe. 및 StringBuilder에는 이러한 수정 사항이 없으며 스레드에 안전하지 않은 것으로 간주될 수 있습니다.
위 답변을 더 잘 이해하려면 StringBuffer와 StringBuilder의 소스 코드 구현을 직접 살펴보는 것이 더 실용적입니다. 프로그래머로서 "의심할 때는 소스 코드를 살펴보세요"가 옳습니다. 물론 조건이 있습니다!
jdk 구현에서 StringBuffer와 StringBuilder는 모두 AbstractStringBuilder에서 상속됩니다. 메서드 앞에 동기화된 무리를 보면 멀티스레딩의 안전성과 비안전성에 대한 대략적인 아이디어를 얻을 수 있습니다. StringBuffer에서.
다음은 AbstractStringBuilder의 구현 원리에 대한 일상적인 이야기입니다. 우리는 StringBuffer를 사용하는 것이 Java에서 문자열 연결의 효율성을 향상시키는 것에 지나지 않는다는 것을 알고 있습니다. 왜냐하면 +가 문자열 연결에 직접 사용되면 jvm은 다음을 생성하기 때문입니다. 여러 String 개체로 인해 일정량의 오버헤드가 발생합니다. AbstractStringBuilder는 추가해야 할 문자열을 저장하기 위해 char 배열을 사용하며, 추가된 문자열 길이가 현재 char 배열 용량을 초과하면 char 배열이 동적으로 확장됩니다. 즉, 더 큰 기간이 다시 적용됩니다. 메모리 공간을 확보한 후 현재 char 배열을 새 위치에 복사합니다. 메모리 재할당 및 복사에 따른 오버헤드가 상대적으로 크기 때문에 메모리 공간을 다시 신청할 때마다 현재 필요한 것보다 더 큰 메모리 공간을 신청해야 합니다. 메모리 공간은 2번입니다.
다음엔 재미있게 놀자! StringBuilder를 사용하여 JVM에서 내부적으로 구현되는 반면, 이전에는 이 연산이 StringBuffer를 사용하여 구현되었습니다.
】 간단한 프로그램을 통해 실행 과정을 살펴보겠습니다.
Listing 1 Buffer.java
public class Buffer { public static void main(String[] args) { String s1 = "aaaaa"; String s2 = "bbbbb"; String r = null; int i = 3694; r = s1 + i + s2; for(int j=0;i<10;j++){ r+="23124"; } } }
Listing 2 버퍼 클래스 바이트코드
Listing 1과 Listing 2를 그에 맞게 변환합니다. ldc 목록 2의 바이트코드에 있는 명령어는 "aaaaa" 문자열을 상수 풀에서 스택 상단으로 로드하고 istore_1은 "aaaaa"를 변수 1에 저장하며 후자는 동일합니다. sipush는 짧은 정수를 로드합니다. 상수 값(- 32768~32767)이 스택의 맨 위로 푸시됩니다. 여기에 상수 "3694"가 있습니다. 더 많은 Java 명령어 세트를 보려면 다른 문서 "Java 명령어 세트"를 참조하세요.
13, 13~17에서 StringBuffer 객체를 새로 만들고 그 초기화 메서드를 호출하는 것을 직접 보면, 20~21에서는 먼저 aload_1을 통해 변수 1을 스택 맨 위로 푸시하고 앞서 언급한 대로 변수 1이 삽입됩니다. 스택 맨 위에는 문자열 상수 "aaaaa"가 있고, Invokevirtual 명령을 통해 StringBuffer의 추가 메서드를 호출하여 "aaaaa"를 함께 연결하고, 이후 24~30초 동안 동일하게 진행됩니다. 마지막으로 33에서 StringBuffer의 toString 함수를 호출하여 String 결과를 얻고 astore를 통해 변수 3에 저장합니다.
이것을 보고 어떤 사람들은 "JVM이 문자열을 연결하기 위해 내부적으로 StringBuffer를 사용하기 때문에 우리는 StringBuffer를 사용할 필요가 없고 그냥 "+"만 사용하면 됩니다!"라고 말할 수도 있습니다. 정말? 물론 그렇지 않습니다. "존재의 이유가 있다"는 말처럼, 다음 루프에 해당하는 바이트코드를 계속해서 살펴보겠습니다.
37~42는 모두 for 루프에 들어가기 전 준비사항입니다. 37과 38은 j를 1로 설정합니다. 44 여기서 j는 if_icmpge를 통해 10과 비교되며, j가 10보다 크면 바로 73으로 점프합니다. 즉, return 문은 함수를 종료합니다. 그렇지 않으면 바이트코드 47~66인 루프에 들어갑니다. 여기서는 문자열 연결을 처리하기 위해 코드에서 StringBuffer를 사용해야 하는 이유를 알기 위해 47~51만 보면 됩니다. 왜냐하면 "+" 작업이 수행될 때마다 jvm은 문자열 연결을 처리하기 위해 새 StringBuffer 객체를 생성해야 하기 때문입니다. 문자열 연결. 많은 문자열 연결 작업이 관련되면 비용이 많이 들 수 있습니다. Java(StringBuffer와 StringBuilder)의 원리와 차이점에 관한 더 많은 기사를 보려면 PHP 중국어 웹사이트를 주목하세요!