티스토리 뷰



■자바의 String에 대해 잘 안다고 말할 수 있을까?


 신용권님이 쓰신 이것이 자바다 책을 두번째 학습하는 중이다. 확실히 느끼는 건데, 1회독과 2회독의 느낌은 정말 다르다는 것을 느끼면서 책을 읽고 있다. 분명, 세번째 이 책을 볼 때는 또 다른 느낌일 것 이라고 확신한다.


 오늘 포스팅의 주제는 Java의 String이다. 과연, 웹 개발자를 목표로 Java를 공부하고 있는  내가 자바의 String에 대해 잘 알고 있다고 말할수 있을까? 라는 생각의 이 포스팅의 시발점이다.


아래의 코드에서 몇개의 객체가 생성이 될까?

public class StringExample { 
  public static void main(String [] args) {
    String name1 = new String("nroo");
    String name2 = "nroo";
    String name3 = "nroo";
  } 
}

 솔직히 나의 생각은 'String은 클래스이므로 참조타입이다. 어 그러면 객체 3개가 만들어 지고, 각각 생성한 객체를 참조하겠네' 였고, 틀렸다. 내가 공부하고 있는 자바는 그리 멍청하고 비 효율적이지 않았고, 나는 자바의 String에 대해 잘 모르고 있었다. 제대로 공부하지 않았음에 반성하고, 성장의 과정이라고 혼자 긍정적인 마인드로 무장해본다.


 Java에서 String은 특별한 참조 자료형이다. String 객체는 자바에 내장된 클래스로 위와 같이 new 키워드로 새로운 객체를 생성할 수도 있고, " "안에 값을 입력하여 생성할 수도 있다. 


 자바의 문자열은 java.lang 패키지의 String클래스의 인스턴스로 관리된다. 소스상에서 문자열 리터럴은 String 객체로 자동 생성되지만, String 클래스의 다양한 생성자를 이용해서 직접 String 객체를 생성해서 사용 할 수도 있다.


 예를 들어, 아래와 같은 작업이 필요하다면 제공되는 생성자를 사용해서 직접 String 객체를 생성해서 사용하면 된다.

public class StringExample { 
  public static void main(String [] args) {
    //배열 전체를 String 객체로 생성
    String str = new(byte[] bytes);
    //배열의 offset 인덱스 위치부터 length만큼 String객체로 생성
    String str2 = 
        new String(byte[] bytes, int offset, int length);
  } 
}

 본론으로 돌아와서, 두 가지 방식 모두 String 객체를 생성한다는 사실은 같지만, JVM이 관리하는 메모리 구조상에서 명백히 다르다. 아래의 그림은 두가지 방법으로 String 객체를 생성했을 때, JVM 메모리상에 어떻게 존재하는지에 대한 이해를 돕는 그림이다.


출처 : http://www.journaldev.com/797/what-is-java-string-pool



 자바의 String은 특별한 '참조 자료형'이다. new 생성자를 이용해서 인스턴스를 생성한 뒤, heap에서 메모리 관리가 이루어 진다는 사실은 다른 참조 자료형과 다를게 없다. 하지만 다른 참조형과는 다르게 변하지 않는다는 특징을 가지고 있다. String is unchanged!!!!


 한번 저장된 String객체의 값은 변하지 않는다. 위의 그림에서 s3 = s3 + s3; 를 실행한다면? CatCat값을 가지는 String 객체를 새로 생성하고, s3는 생성된 인스턴스를 참조하게 된다. 


 결과적으로 String 객체들의 연산이 이루어지면, 새로운 객체를 계속 만들어내기 때문에 메모리 관리 측면에서 상당히 비효율적이다.

 이러한 이유로 만들어진 메모리영역이 Heap 안에 있는 String Constant Pool이다. 여기에는 기존에 만들어진 문자열 값이 저장되어 있고, s1과 s2처럼 리터럴로 생성된 같은 값을 가지는 객체는 같은 레퍼런스를 가지게 된다!!!!


 그렇다면, 아래의 코드에서 생성되는 객체의 수는?

public class StringExample { 
  public static void main(String [] args) {
    String name1 = new String("nroo");
    String name2 = "nroo";
    String name3 = "nroo";
  } 
}

 name1 은 heap 메모리에 개별 객체가 만들어지고, name2와 name3은 String Constant Pool에 만들어진 하나의 객체를 참조한다. 따라서 총 2개의 String 객체가 생성된다. 



댓글
  • 프로필사진 heyhyo 감사합니다~ 이해하기 쉽게 잘 설명해 놓으셨네요^^ 2018.07.17 18:25 신고
  • 프로필사진 nroo nroo 감사합니다:) 2018.07.19 01:21 신고
  • 프로필사진 homrun 이해가 안갔던 부분인데 정말 이해가기 쉽게 설명 잘 해주셨어요,.
    감사합니다.
    2019.03.29 14:43
  • 프로필사진 nroo nroo 홈런님 감사합니다:) 2019.04.04 10:44 신고
  • 프로필사진 rlawldud335 설명을 쉽고 재미있게 잘하시네요! 감사합니다 2019.03.31 14:06
  • 프로필사진 nroo nroo 감사합니다:) 2019.04.04 10:44 신고
  • 프로필사진 ㅅㅇㄴㄹ 좋은 글 감사드립니다! 근데 궁금한게 그러면 s1=s1+s2 라고 하면 어떻게 되는 건가요? 혹시 string constant pool를 참조하는 문자열은 수정 할 수 없나요? 2019.09.10 16:53
  • 프로필사진 nroo nroo java에서 string은 immutable한 특성을 가지고 있는데요, 한번 생성되면 변하지 않는다는 이야기 입니다. string constant pool을 참조하는 문자열을 수정한다는 이야기는 기존에 리터럴 형태로 선언한 String 타입의 변수에 새로이 리터럴 형태의 문자열을 할당 한다는 이야기를 하신거 같은데 이 경우 string constant pool의 새로운 주소를 참조하게 되겠죠? 변경이 아니라 생성과 재할당 이라고 이해하시면 좋을 것 같습니다. s1 + s2의 결과는 두 문자열이 합쳐진 형태의 새로운 문자열을 s1이 참조하게 됩니다:) 천천히 위의 글을 한번더 읽어보시면 이해 되실거에요. 혹시나 부족하다면 다른 좋은 글들 참조하시기 바랄게요! 2019.09.10 22:14 신고
  • 프로필사진 인하대 우연히 들르게 되었는데 깔끔한 정리에 이해가 쏙쏙 되네요
    존경합니다
    2020.11.12 23:30
댓글쓰기 폼