[JAVA]자바의 기본 개념 정리-4.String pool

String 에 대한 더 자세한 설명

이전 포스트에서 말했듯이 String 객체의 값은 변경할 수 없다.
나는 String 객체의 값을 변경 시킬수 있다고 생각하시는 분들을 위해 아래 예제를 통해 설명하겠다.

1
2
3
String a = "Hello";
a = a+" World";
System.out.println(a); //Hello World

이 예제를 보면 a가 참조하는 메모리의 Hello 라는 값에 World 라는 문자열을 더해서 String 객체의 값을 변경 시킨 것으로 보인다

하지만 실제로는 메모리에 Hello World 를 다시 만들고 a를 다시 참조하게 한다.

간단하게 String 클래스의 immutable(불변) 에 대하여 복습 하였다.

String pool 이란??

String은 자바 개발자라면 자주 쓰게되는 자료형 이다.
간혹 자바에서 ==연산자를 이용해서 문자열을 비교하려고 할때 원치 않는 결과를 얻었던 경험들이 있을 것이다.

스트링은 두가지 생성 방식이 있고 그에 따라 각각 차이점이 존재한다.

  1. new 연산자를 이용한 방식
  2. 리터럴을 이용한 방식

new를 통해 String을 생성하면 Heap영역에 존재하게 되고 리터럴을 이용할 경우 String constant pool이라는 영역에 존재하게 된다.

예제를 통해 쉽게 설명해 보도록 하겠다.

1
2
3
4
5
String a = "Hello";
String b = "Hello";
String c = new String("Hello");
System.out.println(a==b); //true
System.out.println(a==c); //false

위에 예제의 결과에서 왜 3가지 객체가 다 같은 값을 가지고 있음에도 불구하고 비교 결과가 다른지 의문을 가진 분들이 있을것이다.

우선 == 연산은 값을 비교하는것이 아니라 같은 메모리를 참조하는지 비교하는 것이다.

  • a의 경우 Hello 라는 문자열을 String pool 에 넣게 된다.
  • b의 경우는 이미 같은 문자열이 String pool 에 존재하기에 같은 값을 참조하게 된다.
  • c의 경우에는 new 연산자를 사용하여 새로운 객체를 명시적으로 생성하도록 했기 때문에 String pool이 아닌 다른 주소값을 참조하게된다.

이러한 이유로 위와 같은 결과를 얻을 수 있다.

이 예제를 통해 왜 String 객체의 값을 변경할 수 없어야 하는지 이유도 알 수 있다.
만약에 String 객체의 값의 변경이 가능하다면 a의 값을 변경 하였을때 원치 않게 b의 값도 변경될 수 있다.

String 객체의 값을 비교하는 equals()

equals() 메소드를 이용하여 두 문자열 객체의 실제 값을 비교할 수 있다.

그렇기 때문에 문자열 비교는 equals() 를 사용하는 것이 좋지만 속도적인 부분이나 메모리 부분 때문에 ==을 사용해야한다면 방법은 있다.

intern() 메소드를 사용하는 방법이다.

intern()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
String a = "Hello";
String b = new String("Hello");
String c = b.intern();
System.out.println(a.equal(b)); // true
System.out.println(a==c); // true
```

**intern()** 메소드를 사용하면 해당 리터럴이 pool 에 존재하는지 화가인하고 존재하면 해당 pool 에 있는 리터럴을 리턴하고 없다면 리터럴을 pool 에 집어넣는다.

그렇기 때문에 c의 경우는 String c = "Hello" 로 해석할 수 있고 pool 에 이미 a가 만든 Hello 가 존재하므로 a와 같은 주소를 참조하게 된다.

아마도 **intern()** 메소드보다 **equals()** 메소드를 더 많이 사용하게 되겠지만 만약 사용하게 된다면 아래와 같이 사용할 수 있지 않을까 싶다.

```java
String id = "user";
String compareId = UserDto.getId().intern();
if(id == user){
...
}

그냥 이렇게도 사용할 수 있지 않을까 싶어 내가 만든 예시이다.

속도나 메모리를 엄청 신경 써야 하지 않는다면 문자열 비교는 equals()로 습관화 하는것이 좋은 방법일것 같다.

String pool 의 위치

String pool 은 java 6 버전까지 Perm 영역이었다.

하지만 Perm 영역은 고정된 사이즈이며 Runtime 에 사이즈가 확장되지 않는다

그래서 intern 되는 String 값이 커지면 OutOfMemoryException을 발생시킬 수 있었고 그에따라 java 7 버전에서 heap 영역으로 String pool 의 위치를 변경하였다.