원본 측면에서 간단하게 볼 때 StringBuilder와 StringBuffer의 공통점(전면 해석)

개요
StringBuilder와 StringBuffer는 헷갈리기 쉬운 두 가지 개념으로 본고는 원본에서 착안하여 이들의 공통점과 차이점을 간단하게 본다.
쉽게 알 수 있는 것은 이 두 가지 중 하나는 라인이 안전하고 라인이 안전한 효율이 낮다는 것이다.
javadoc에 대한 설명
자바doc는 원본을 쓰는 사람이 쓴 주석입니다. 먼저 자바doc를 보십시오.
StringBuilder
A mutable sequence of characters. This class provides an API compatible with StringBuffer, but with no guarantee of synchronization. This class is designed for use as a drop-in replacement for StringBuffer in places where the string buffer was being used by a single thread (as is generally the case). Where possible, it is recommended that this class be used in preference to StringBuffer as it will be faster under most implementations.
The principal operations on a StringBuilder are the append and insert methods, which are overloaded so as to accept data of any type. Each effectively converts a given datum to a string and then appends or inserts the characters of that string to the string builder. The append method always adds these characters at the end of the builder; the insert method adds the characters at a specified point.
For example, if z refers to a string builder object whose current contents are "start", then the method call z.append("le") would cause the string builder to contain "startle", whereas z.insert(4, "le") would alter the string builder to contain "starlet".
In general, if sb refers to an instance of a StringBuilder, then sb.append(x) has the same effect as sb.insert(sb.length(), x).
Every string builder has a capacity. As long as the length of the character sequence contained in the string builder does not exceed the capacity, it is not necessary to allocate a new internal buffer. If the internal buffer overflows, it is automatically made larger.
Instances of StringBuilder are not safe for use by multiple threads. If such synchronization is required then it is recommended that java.lang.StringBuffer be used.
Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.
Since:
1.5
Author:
Michael McCloskey
See Also:
java.lang.StringBuffer
java.lang.String
StringBuffer
A thread-safe, mutable sequence of characters. A string buffer is like a String, but can be modified. At any point in time it contains some particular sequence of characters, but the length and content of the sequence can be changed through certain method calls.
String buffers are safe for use by multiple threads. The methods are synchronized where necessary so that all the operations on any particular instance behave as if they occur in some serial order that is consistent with the order of the method calls made by each of the individual threads involved.
The principal operations on a StringBuffer are the append and insert methods, which are overloaded so as to accept data of any type. Each effectively converts a given datum to a string and then appends or inserts the characters of that string to the string buffer. The append method always adds these characters at the end of the buffer; the insert method adds the characters at a specified point.
For example, if z refers to a string buffer object whose current contents are "start", then the method call z.append("le") would cause the string buffer to contain "startle", whereas z.insert(4, "le") would alter the string buffer to contain "starlet".
In general, if sb refers to an instance of a StringBuffer, then sb.append(x) has the same effect as sb.insert(sb.length(),
Whenever an operation occurs involving a source sequence (such as appending or inserting from a source sequence), this class synchronizes only on the string buffer performing the operation, not on the source. Note that while StringBuffer is designed to be safe to use concurrently from multiple threads, if the constructor or the append or insert operation is passed a source sequence that is shared across threads, the calling code must ensure that the operation has a consistent and unchanging view of the source sequence for the duration of the operation. This could be satisfied by the caller holding a lock during the operation's call, by using an immutable source sequence, or by not sharing the source sequence across threads.
Every string buffer has a capacity. As long as the length of the character sequence contained in the string buffer does not exceed the capacity, it is not necessary to allocate a new internal buffer array. If the internal buffer overflows, it is automatically made larger.
Unless otherwise noted, passing a null argument to a constructor or method in this class will cause a NullPointerException to be thrown.
As of release JDK 5, this class has been supplemented with an equivalent class designed for use by a single thread, StringBuilder. The StringBuilder class should generally be used in preference to this one, as it supports all of the same operations but it is faster, as it performs no synchronization.
Since:
JDK1.0
Author:
Arthur van Hoff
See Also:
java.lang.StringBuilder
java.lang.String
javadoc 소결
위에서 볼 수 있듯이
StringBuffer와 StringBuilder는 모두 가변적인 String이라고 볼 수 있습니다.
StringBuffer는 라인이 안전합니다. 먼저 나타나면 JDK1.0에 있습니다.
StringBuilder는 비스레드가 안전합니다. 나중에 나타나면 JDK1.5에 있습니다.
두 인터페이스는 완전히 동일하며 StringBuilder가 더 빠릅니다.
사실 정상적으로 사용하면 이 몇 가지를 알면 좋겠지만 원본 코드에서 어떻게 실현되는지 보고 싶어요.
원본 코드
어떻게 스레드 안전을 실현합니까
원본을 보면 알 수 있듯이 이 두 사람은 모두 추상적인 클래스인 AbstractStringBuilder를 계승했다

public final class StringBuffer
 extends AbstractStringBuilder
 implements java.io.Serializable, CharSequence

public final class StringBuilder
 extends AbstractStringBuilder
 implements java.io.Serializable, CharSequence 
코드량도 크지 않다. StringBuilder440행 코드, StringBuffer718행 코드, 가장 많은 것은 AbstractStringBuilder로 모두 1440행 코드이다.
코드를 몇 가지 측면에서 보면 첫째, 관건적인 내부 구조가 어떤 것인지, 둘째, 우리가 자주 사용하는 함수가 어떻게 실현되는지.String은 변하지 않기 때문에 상량 탱크에 놓여 있습니다.StringBuilder와 StringBuffer는 char 수조로 이루어져야 한다고 추측합니다.

/**
 * The value is used for character storage.
 */
 char[] value;

 /**
 * The count is the number of characters used.
 */
 int count;
알 수 있듯이value로 데이터를 저장하고count로 길이를 표시합니다.
몇 가지 흔히 볼 수 있는 방법의 다른 실현을 보다.
StringBuffer

 @Override
 public synchronized StringBuffer append(String str) {
 toStringCache = null;
 super.append(str);
 return this;
 }

 /**
 * @throws StringIndexOutOfBoundsException {@inheritDoc}
 */
 @Override
 public synchronized StringBuffer insert(int offset, String str) {
 toStringCache = null;
 super.insert(offset, str);
 return this;
 }

 @Override
 public synchronized String toString() {
 if (toStringCache == null) {
  toStringCache = Arrays.copyOfRange(value, 0, count);
 }
 return new String(toStringCache, true);
 }
StringBuilder

@Override
 public StringBuilder append(String str) {
 super.append(str);
 return this;
 }

 /**
 * @throws StringIndexOutOfBoundsException {@inheritDoc}
 */
 @Override
 public StringBuilder insert(int offset, String str) {
 super.insert(offset, str);
 return this;
 }
 
 @Override
 public String toString() {
 // Create a copy, don't share the array
 return new String(value, 0, count);
 }
코드에서 알 수 있듯이 대부분의 경우 StrinbBuffer는 라인 안전을 위해synchronized 키워드를 추가했을 뿐이다.하지만 toString은 방법이 다르니 이 다음에 다시 이야기하자.
크기 초기화 및 증가 방법
기왕 실제적으로 하나의 수조라면 수조가 시작하는 크기와 성장 방법이 매우 중요하다. 우리는 코드를 통해 한번 보자.

/**
 * Constructs a string buffer with no characters in it and an
 * initial capacity of 16 characters.
 */
 public StringBuffer() {
 super(16);
 }

 /**
 * Constructs a string builder with no characters in it and an
 * initial capacity of 16 characters.
 */
 public StringBuilder() {
 super(16);
 }
이 두 기본 구조 함수는 기본 그룹의 크기가 16이라는 것을 알 수 있다.
왜 16이죠?나는 이해하지 못했다.
다음 관심은 어떻게 증가합니까?append의 실현을 봅시다.

public AbstractStringBuilder append(String str) {
 if (str == null)
  return appendNull();
 int len = str.length();
 ensureCapacityInternal(count + len);
 str.getChars(0, len, value, count);
 count += len;
 return this;
 }


 /**
 * This method has the same contract as ensureCapacity, but is
 * never synchronized.
 */
 private void ensureCapacityInternal(int minimumCapacity) {
 // overflow-conscious code
 if (minimumCapacity - value.length > 0)
  expandCapacity(minimumCapacity);
 }
 
 /**
 * This implements the expansion semantics of ensureCapacity with no
 * size check or synchronization.
 */
 void expandCapacity(int minimumCapacity) {
 int newCapacity = value.length * 2 + 2;
 if (newCapacity - minimumCapacity < 0)
  newCapacity = minimumCapacity;
 if (newCapacity < 0) {
  if (minimumCapacity < 0) // overflow
  throw new OutOfMemoryError();
  newCapacity = Integer.MAX_VALUE;
 }
 value = Arrays.copyOf(value, newCapacity);
 }
위의 세 가지 방법은 어떻게 용량을 확대하는지 설명하였다.
현재 용량*2+2
새로 추가된 길이가 이 값보다 크면 새로 추가된 값으로 설정합니다
넘치면 OutOfMemoryError
StringBuffer에서 toString의 실현

/**
 * A cache of the last value returned by toString. Cleared
 * whenever the StringBuffer is modified.
 */
 private transient char[] toStringCache;

 @Override
 public synchronized StringBuffer append(String str) {
 toStringCache = null;
 super.append(str);
 return this;
 }
 @Override
 public synchronized String toString() {
 if (toStringCache == null) {
  toStringCache = Arrays.copyOfRange(value, 0, count);
 }
 return new String(toStringCache, true);
 }
볼 수 있듯이 하나의 수조 toStringCache를 정의했는데 데이터가 변할 때마다 이것을null로 설정합니다.toString에서 현재 데이터에서 다시 가져옵니다.
transient 키워드는 이 그룹이 서열화되는 것을 피하기 위해서입니다.
작은 매듭
사실 자바 자체의 원본 코드는 비교적 간단하게 썼다. 지식을 배우면 원본에서 착안하여 많은 원리를 더욱 깊이 이해할 수 있다.본고는 단지 일부 원본을 간단하게 열거했을 뿐, StringBuffer와 StringBuilder의 공통점과 차이점을 간단하게 설명한다.관심 있는 친구는 스스로 한번 볼 수 있다.
이상의 이 편은 원본 차원에서 간단하게 볼 수 있는 String Builder와 String Buffer의 공통점(전면적인 해석)이 바로 편집자가 여러분에게 공유한 모든 내용입니다. 참고도 해주시고 저희도 많이 사랑해 주시기 바랍니다.

좋은 웹페이지 즐겨찾기