String 에 대한 더 자세한 설명
이전 포스트에서 말했듯이 String 객체의 값은 변경할 수 없다.
나는 String 객체의 값을 변경 시킬수 있다고 생각하시는 분들을 위해 아래 예제를 통해 설명하겠다.1
2
3String a = "Hello";
a = a+" World";
System.out.println(a); //Hello World
이 예제를 보면 a가 참조하는 메모리의 Hello 라는 값에 World 라는 문자열을 더해서 String 객체의 값을 변경 시킨 것으로 보인다
하지만 실제로는 메모리에 Hello World 를 다시 만들고 a를 다시 참조하게 한다.
간단하게 String 클래스의 immutable(불변) 에 대하여 복습 하였다.
String pool 이란??
String은 자바 개발자라면 자주 쓰게되는 자료형 이다.
간혹 자바에서 ==연산자를 이용해서 문자열을 비교하려고 할때 원치 않는 결과를 얻었던 경험들이 있을 것이다.
스트링은 두가지 생성 방식이 있고 그에 따라 각각 차이점이 존재한다.
- new 연산자를 이용한 방식
- 리터럴을 이용한 방식
new를 통해 String을 생성하면 Heap영역에 존재하게 되고 리터럴을 이용할 경우 String constant pool이라는 영역에 존재하게 된다.
예제를 통해 쉽게 설명해 보도록 하겠다.
1 | String a = "Hello"; |
위에 예제의 결과에서 왜 3가지 객체가 다 같은 값을 가지고 있음에도 불구하고 비교 결과가 다른지 의문을 가진 분들이 있을것이다.
우선 == 연산은 값을 비교하는것이 아니라 같은 메모리를 참조하는지 비교하는 것이다.
- a의 경우 Hello 라는 문자열을 String pool 에 넣게 된다.
- b의 경우는 이미 같은 문자열이 String pool 에 존재하기에 같은 값을 참조하게 된다.
- c의 경우에는 new 연산자를 사용하여 새로운 객체를 명시적으로 생성하도록 했기 때문에 String pool이 아닌 다른 주소값을 참조하게된다.
이러한 이유로 위와 같은 결과를 얻을 수 있다.
이 예제를 통해 왜 String 객체의 값을 변경할 수 없어야 하는지 이유도 알 수 있다.
만약에 String 객체의 값의 변경이 가능하다면 a의 값을 변경 하였을때 원치 않게 b의 값도 변경될 수 있다.
String 객체의 값을 비교하는 equals()
equals() 메소드를 이용하여 두 문자열 객체의 실제 값을 비교할 수 있다.
그렇기 때문에 문자열 비교는 equals() 를 사용하는 것이 좋지만 속도적인 부분이나 메모리 부분 때문에 ==을 사용해야한다면 방법은 있다.
intern() 메소드를 사용하는 방법이다.
intern()
1 | String a = "Hello"; |
그냥 이렇게도 사용할 수 있지 않을까 싶어 내가 만든 예시이다.
속도나 메모리를 엄청 신경 써야 하지 않는다면 문자열 비교는 equals()로 습관화 하는것이 좋은 방법일것 같다.
String pool 의 위치
String pool 은 java 6 버전까지 Perm 영역이었다.
하지만 Perm 영역은 고정된 사이즈이며 Runtime 에 사이즈가 확장되지 않는다
그래서 intern 되는 String 값이 커지면 OutOfMemoryException을 발생시킬 수 있었고 그에따라 java 7 버전에서 heap 영역으로 String pool 의 위치를 변경하였다.