뭉
노재능 록리형 개발자
뭉
전체 방문자
오늘
어제
  • 분류 전체보기 (27)
    • Java (18)
      • Grammer (14)
      • Problem Solving (4)
    • JavaScript (0)
      • Grammer (0)
      • jQuery (0)
    • Spring (0)
    • DB (9)
      • SQL (6)
      • JPA (3)
    • Storage (0)
    • ETC (0)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
뭉

노재능 록리형 개발자

String Class (1) - Immutable과 StringBuilder/StringBuffer
Java/Grammer

String Class (1) - Immutable과 StringBuilder/StringBuffer

2022. 3. 26. 17:38

String Pool과 Immutable

String은 객체입니다. 원시타입처럼 사용하지만 실제론 new를 통해 생성이 가능한 객체입니다.

그렇다면 {} 사용한 방식과는 차이가 무엇일까요?

코드를 통해 알아보겠습니다.

public static void main(String[] args) {
    String text1 = "hello";
    String text2 = "hello";
    String text3 = new String("hello");
    String text4 = new String("hello");

    System.out.println(text1 == text2);       //true
    System.out.println(text3 == text4);       //false
}

위와 같이 {}를 사용한 String 객체들은 값이 같다면 동일한 주소값을 가집니다.

new로 생성한 String 객체들은 주소값이 다르죠? 왜 이러한 결과가 나오는 걸까요?

Heap 영역에는 String Pool이란 특별한 영역이 존재하는데 {}로 생성할 경우 문자열의 값은 이 영역에 할당됩니다.

String Pool의 특이한 점은 String 객체 생성 시 동일한 값을 가지고 있다면 같은 값을 가진 String 객체의 참조값을 반환한다는 것입니다.

반대로 new를 통한 String 객체 생성은 매번 Heap 영역에 새로운 객체를 생성합니다.

이에 따라 new를 사용한 객체생성보단 {}를 사용한 객체생성을 지향하는 것이 옳습니다.

String은 불변객체라는 말을 들어보셨나요?

위 내용과 연관지어 생각하면 String이 왜 불변객체일수 밖에 없는지 이해하실 겁니다.

같은 값을 가진다면 String Pool로 인하여 String 객체는 공유됩니다.

공유되기 위한 필수조건 중 하나는 불변이여야합니다. 값이 변경되지 않아야 비로소 서로의 참조값을 가르켜 공유할수 있는 것이지요.

 

equals와 hashCode

위에선 같은 값을 가지면 String Pool로 인하여 String 객체는 공유된다 말씀드렸습니다.

즉 우리가 중점으로 봐야할 점은 문자열의 값입니다.

이에 따라 자바에는 문자열의 값에 따라 Object 클래스의 equals와 hashCode를 오버라이딩 했습니다.

따라서 ==을 사용할 필요없이 동등비교는 equals를 사용하면 됩니다. hashCode 또한 마찬가지입니다. 값에 따라 해시값이 생성됩니다.

String text1 = "hello";
String text2 = "hello";
String text3 = new String("hello");
String text4 = new String("hello");
String[] texts = {text1, text2, text3, text4};

System.out.println(text1.equals(text2));  //true
System.out.println(text3.equals(text4));  //true
Arrays.stream(texts).forEach(s -> System.out.println(s.hashCode()));    //모두 99162322

 

StringBuilder와 StringBuffer

문자열이 불변객체 임에 따라 +와 같은 연산을 진행했을 때 새로운 문자열이 만들어지고 이를 gc(Garbage Collector)가 관리합니다.

아무리 gc가 관리한다고 해도 새로운 객체들이 계속 생성되는 것은 메모리 관리 측면에서 좋지 못하겠지요.

이에 따라 자바에선 문자열을 가변적으로 사용할수 있게 StringBuilder와 StringBuffer를 제공합니다.

코드를 통해 알아봅시다.

StringBuilder text = new StringBuilder();

text.append("Hello");
text.append("World");
text.append("!!!");

String result = text.toString();
String reverseResult = text.reverse().toString();

System.out.println(result);             //HelloWorld!!!
System.out.println(reverseResult);      //!!!dlroWolleH

원래라면 +로 계속 더해서 새로운 객체를 만들어야하지만 append를 사용해 객체 하나에서 연산을 진행하고 있습니다.

거기다 문자열을 거꾸로 만들수 있는 reverse 메서드도 지원하고 있죠.

문자열로 변경시엔 toString을 사용하면 됩니다.

 

그렇다면 StringBuilder와 StringBuffer 뭐가 다를까요?

StringBuffer는 메서드들에 모두 synchronized 키워드가 붙여 있습니다. 따라서 이 둘의 차이는 "동기화가 지원되는가 안되는가의 차이점"입니다.

하지만 제 경험 상 문자열 데이터를 다른 스레드들과 공유하는 상황은 거의 없었던 것 같습니다.

데이터를 공유한다면 StringBuffer를 데이터를 공유하지 않는다면 StringBuilder를 사용하면 되겠습니다.

'Java > Grammer' 카테고리의 다른 글

String Class (3) - 정규표현식  (0) 2022.04.02
String Class (2) - 주요 메서드  (0) 2022.03.27
추상클래스와 인터페이스의 차이  (0) 2022.01.16
Call by value  (0) 2021.12.28
생성자와 상속의 관계  (0) 2021.12.25
    'Java/Grammer' 카테고리의 다른 글
    • String Class (3) - 정규표현식
    • String Class (2) - 주요 메서드
    • 추상클래스와 인터페이스의 차이
    • Call by value
    뭉
    뭉
    노재능 록리형 개발자

    티스토리툴바