항상 읽어도 이해하기 힘들 부분이었으나, 이번 기회에 확실히 이해하고 정리를 하게 되었다.
Java에서 String을 생성하는 방식은 두가지가 있다.
new
연산자를 이용하는 방법 (String str = new String("Hello"));- 리터럴을 이용하는 방법 (String str = "Hello");
new
연산자를 통해서 생성하게 되면 String은 Heap
영역에 존재하게 된다.
하지만 리터럴을 이용할 경우 string contstant pool
이라는 영역에 존재하게 된다. (constoanl pool은 PermGen
영역에 존재하게 된다.)
차이점을 살펴보자.
@org.junit.Test
public void testStringEquality(){
final String literal = "Hello";
final String object = new String("Hello");
Assert.assertTrue(literal.equals(object));
Assert.assertFalse(literal == object);
}
위의 테스트를 보면 두 String의 동등성(equals
)는 true이나, 동일성(==
)은 false가 나오는 것을 볼 수 있다.equals
은 문자열을 비교하기 때문에 true, ==
은 객체의 주소값을 비교하기 때문에 false가 나옴
=> 일반객체 처럼 Heap
영역에 생성된 String 객체와 리터럴을 이용해 string constant pool
에 저장된 String 객체의 주소는 다를 수 밖에 없기 때문이다.
내부적으로 어떻게 동작할까?
String을 리터럴로 선언할 경우 내부적으로 String의 intern()메서드가 호출되게 된다. intern() 메서드는 주어진 문자열이 string constant pool
에 존재하는지 검색하고 있다면 그 주소값을 반환, 없다면 string constant pool
에 넣고 새로운 주소값을 반환한다.
@org.junit.Test
public void testStringIntern(){
final String literal = "Hello";
final String object = new String("Hello");
final String intern = literal.intern();
Assert.assertTrue(literal.equals(object));
Assert.assertFalse(literal == object);
Assert.assertTrue(literal.equals(intern));
Assert.assertTrue(literal == intern);
}
위의 코드를 보면 intern()
메서드를 호출한 결과값을 intern 변수에 할당되는 것을 볼 수 있다. 그 후 literal과 intern의 동일성(==
)과 동등성(equals
)를 비교해보면 둘다 true값이 나와 테스트에 성공하게 된다.
리터럴로 "Hello"라는 문자열이 string constant pool
에 저장되었고, inter() 메서드를 호출하면서 string constant pool
에서 Hello
라는 문자열을 검색하고 이미 존재하기 때문에 "Hello" 의 동일한 주소값을 반환하게 되어 true가 나오게 된다.
'프로그래밍 노트 > JAVA' 카테고리의 다른 글
[JAVA] 스트림(Stream)의 종류 (0) | 2019.06.17 |
---|---|
[JAVA] Stream API 소개 (0) | 2019.06.17 |
[JAVA] 익명객체_익명 구현 객체 생성 (0) | 2019.04.15 |
[JAVA] 익명객체_익명 자식 객체 생성 (0) | 2019.04.15 |
[JAVA] 람다식 클래스 멤버와 로컬 변수 사용 (0) | 2019.04.15 |