자바에서 String를 객체를 생성하는 방법은 크게 2가지 입니다.
첫번째는 리터럴(따옴표)을 이용하는 것이며, 두번째는 String 클래스의 생성자를 이용하는 방식이며,
// 1. 리터럴 방식
String b = "hello";
// 2. String 클래스의 생성자 방식
String a = new String("hello");
이펙티브 자바에 따르면, 생성자를 이용하는 방식은 절대 하지 말라고 합니다.
리터럴 방식 - String Constant Pool 영역에 생성
생성자 방식 - 객체를 Heap 영역에 생성
리터럴 방식의 경우 String Constant Pool을 먼저 조회하고 hello문자열을 검색합니다. 없으면 생성하고, 만약 있다면 또 생성하지 않고 주소값을 참조합니다.
생성자 방식의 경우 객체를 생성할때마다 heap영역에 저장됩니다.
리터럴 방식의 경우 같은 주소를 참조하기 때문에 주소값 비교가 true, 생성자 방식의 경우 false 입니다.
class Main {
public static void main(String[] args) {
// 1. 리터럴 방식
String a = "hello";
String b = "hello";
// 2. String 클래스의 생성자 방식
String c = new String("hello");
String d = new String("hello");
System.out.println(a == b); // true
System.out.println(c == d); // false
}
}
String 클래스에는 intern 메소드가 있습니다. 템플릿 리터럴로 생성될때 내부적으로 수행됩니다.
intern은 해당 객체가 String Constant Pool에 있는지 검사하고 없으면 추가 하고 참조값을 리턴, 있으면 객체를 반환합니다.
class Main {
public static void main(String[] args) {
// 1. 리터럴 방식
String a = "hello";
String b = "hello";
// 2. String 클래스의 생성자 방식
String c = new String("hello");
String d = new String("hello");
System.out.println(a == b); // true
System.out.println(c == d); // false
c = c.intern();
d = d.intern();
System.out.println(a == c); // true
System.out.println(c == d); // true
}
}
자바에서 문자열을 생성할때 반드시 리터럴을 사용합시다.
생성자 방식은 쓸데없는 인스턴스를 생성하지만, 리터럴 방식은 객체를 재사용함이 보장되어 메모리를 효율적으로 사용할 수 있습니다.