코딩마을방범대

[Java] String, StringBuffer, StringBuilder의 차이점 본문

💡 백엔드/Java

[Java] String, StringBuffer, StringBuilder의 차이점

신짱구 5세 2023. 7. 28. 14:21
728x90

 

 

여태 문자열을 이어붙일 때 StringBuilder 같은 건 선언하기 귀찮기도 하고 그렇게 친숙하진 않아서 String + 로 추가해왔는데

StringBuilder와 StringBuffer에 대해 알아봐야할 필요성을 느꼈다.

 

 


 

String

  • 불변(immutable) 자료형
    ( 인스턴스 생성 시 생성자의 인자 value는 상수(final)로 선언되어있다. )
String 객체를 불변하게 설계한 이유는 캐싱, 보안, 동기화, 성능측면 이점을 얻기 위해서이다.

1. 캐싱 : String을 불변하게 함으로써 String pool에 각 리터럴 문자열의 하나만 저장하며 다시 사용하거나 캐싱에 이용가능하며 이로 인해 힙 공간을 절약할 수 있다는 장점이 있다. 

2. 보안 : 예를 들어 데이터베이스 사용자 이름, 암호는 데이터베이스 연결을 수신하기 위해 문자열로 전달되는데, 만일 번지수의 문자열 값이 변경이 가능하다면 해커가 참조 값을 변경하여 애플리케이션에 보안 문제를 일으킬 수 있다.

3. 동기화 : 불변함으로써 동시에 실행되는 여러 스레드에서 안정적이게 공유가 가능하다.

 

 

String 객체는 한 번 생성하면 상수값을 가진 객체로 생성되어, concat 또는 + 또는 덮어쓰기 같은 수정을 진행해도

실질적인 값은 변경되지 않고 새로운 String을 생성한 후 변수가 참조하는 Heap 영역의 객체 주소값이 변경되는 것이다.

 

새로운 String을 생성하는 것이 무슨 말이냐 하면,

 

만약 "hello"와 "world"라는 문자열을 합치려고 할 때 + 를 사용했다면 StringBuilder를 생성해 append를 시켜준 후 toString() 메소드를 이용해 String 값으로 변환하여 돌려준다.

// 아래 두 개의 로직이 동일하다.
String str1 = "hello" + "world";
String str2 = new StringBuilder("hello").append("world").toString();

 

concat을 사용했다면 생성자를 이용해 새로운 String을 생성한 후 리턴해준다.

아래는 String 클래스의 concat 메소드이다.

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);
}

 

 

따라서 변경된 후의 객체 주소값이 해당 변수에 참조가 되고,

기존의 String 객체는 Heap 영역에 떠돌다가 GC(가비지 컬렉션)에 의해 지워진다.

 

가비지 컬렉션은 Unreachable 상태인 객체를 제거한다.
Reachable          
: 객체가 참조되고 있는 상태

Unreachable       : 객체가 참조되고 있지 않은 상태

 

 


 

리터럴과 생성자를 이용한 String 생성 시의 차이점

리터럴 string constant pool 이라는 영역에 존재
생성자 Heap 영역에 존재
리터럴로 선언 시
내부적으로 String의 intern() 메소드가 호출되고,
intern() 메소드는 주어진 문자열이 pool 에 존재하는지 검색하고 있다면 그 주소값을 반환하고
없으면 pool에 생성 후 새로운 주소값을 반환한다.

 

 


 

 

 

 

 

StringBuffer & StringBuilder

  • 가변(mutable)적
    ( 내부 Buffer(데이터를 임시로 저장하는 메모리)에 문자열을 저장한 후 수정,삭제 작업을 한다. )
  • 기본 16 버퍼 크기로 생성된 후 문자열 연산 등으로 기존 객체의 공간이 부족하게 되는 경우,
    기존의 버퍼 크기를 늘리며 유연하게 동작

 


 

StringBuffer와 StringBuilder의 차이점

클래스 설명
StringBuffer 각 메소드별로 Synchronized Keyword가 존재하여, 멀티스레드 환경에서도 동기화를 지원
StringBuilder 동기화를 보장하지 않음
( 쓰레드가 객체에 접근해서 변경을 하면 기다려주지 않음 )
Synchronized Keyword
여러개의 스레드가 한 개의 자원에 접근할려고 할 때,
현재 데이터를 사용하고 있는 스레드를 제외하고 나머지 스레드들이 데이터에 접근할 수 없도록 막는 역할을 수행

 

 

 

 


 

 

 

 

결론

클래스 설명
String 문자열 추가 연산이 적고, 쓰레드 세이프 환경일 경우 ( 간단하게 사용 )
StringBuffer 문자열 추가 연산이 많고, 쓰레드 세이프 환경일 경우
StringBuilder 문자열 추가 연산이 많고, 단일 쓰레드 환경이고, 빠른 연산이 필요한 경우

 

 


 

 

💡 연산이 많은 경우 💡

StringBuilder  >>  StringBuffer  >>  String

 

 

 

 

 


 

 

 

 

 

문자열 자료형의 값 비교

 

String은 equals()를 통해 문자열 데이터 동등 비교가 가능하다.

 

하지만 StringBuilder와 StringBuffer는 equals 메소드를 오버라이딩하지 않기 때문에 문자열 데이터를 비교할 수 없어 ==과 같은 결과를 가져온다.

 

따라서 StringBuilder와 StringBuffer는 toString()을 이용해 String으로 변환하여 비교해야 한다.

== 는 문자열 데이터를 비교하는 것이 아닌,
동일한 객체를 참조( = 힙 영역의 객체 주소를 비교 )하는지에 대한 결과가 출력된다.
StringBuffer sb = new StringBuffer("hello");
StringBuffer sb2 = new StringBuffer("hello");

System.out.println(sb == sb2); // false
System.out.println(sb2.equals(sb)); // false
System.out.println(sb2.toString().equals(sb.toString())); // true

 

 

 


참고사이트

[자바] String, StringBuilder, StringBuffer의 차이

☕ 자바 String / StringBuffer / StringBuilder 차이점 & 성능 비교

 

 

728x90