변수에 저장되기 전의 값을 리터럴이라고 한다.
int score = 100; // 변수 : score
final int MAX = 100; // 상수 : MAX
자바에는 String 을 선언하는 방법이 리터럴과 객체로 선언할 수 있다.
//리터럴
String a = "hello";
String b = "hello";
//객체
String c = new String("hello");
String d = new String("hello");
System.out.println(a.equals(b)); // true
System.out.println(a == b); // true
System.out.println(c.equals(d)); // true
System.out.println(c == d); // false
System.out.println(a.equals(c)); // true
System.out.println(a == c); // false
리터럴 선언 방식은 Heap 영역 안에 있는 String Constant Pool(상수풀) 에 위치한다.
String Constant Pool 에 이미 존재하는 문자열이라면 같은 주소값을 공유한다.
따라서 변수 a, b 는 비교하였을 때, 문자열과 주소값이 모두 같은 것을 확인할 수 있다.
String Constant Pool 이란
자바 메모리 중 Heap 영역 안에 위치하여 String 을 별도로 관리하는 장소다.
Heap 안에 있기 때문에 모든 스레드가 공유할 수 있고 가비지 콜렉터의 대상이 된다.
객체 선언 방식은 Heap 영역에 할당된다.
새로운 인스턴스를 생성할 때마다 Heap 영역에 객체가 새로 생긴다.
따라서 변수 c, d 를 비교하였을 때 문자열은 같지만 Heap 영역에서 서로 다른 객체로 생성되었기 때문에 주소값은 다르다.
문자열 리터럴은 String Constant Pool 영역에, 객체는 Heap 영역안에 위치하므로
변수 a, c 는 서로 다른 주소값을 참조한다.
System.out.println(a == c.intern()); //true
intern()
메서드는 String Constant pool 에서 리터럴 문자열이 있으면 반환하고, 없다면 새로 문자열을 넣어주고 그 주소값을 반환한다.
new 연산자로 생성한 변수 c 에 intern()
메서드를 적용하면 리터럴 변수인 a 와 참조하는 주소값이 같아진다.
intern()
메소드 실행상수풀이라는 특별한 메모리 영역에 저장된다.
서로 같은 문자열 리터럴을 사용하는 경우, 동일한 객체로 인식된다.
==
연산자를 사용하여 동등성을 비교할 수 있다.
자바는 상수풀에서 중복된 문자열을 관리하므로 같은 문자열 리터럴을 사용하면 같은 객체를 참조하게 된다.
new 연산자로 문자열을 생성하면 새로운 객체가 heap 메모리에 할당된다.
동일한 문자열이라도 별도의 객체로 취급된다.
불필요한 메모리 사용이 발생할 수 있다.
==
로 동등성을 비교하면 객체의 참조값을 비교하게 되므로 equals()
를 사용하여 내용을 비교해야 한다.
일반적으로 문자열을 다룰 때는 리터럴 방식을 사용하는 것이 권장되며, 이는 코드의 가독성을 높이고 불필요한 메모리 사용을 최소화할 수 있다.