# Java: 문자열 리터럴 vs new String() 객체 생성 차이
---
## 1. 개요
Java에서 문자열은 두 가지 방식으로 생성할 수 있다:
```java
String s1 = "hello"; // 리터럴 방식
String s2 = new String("hello"); // new 키워드 방식
```
두 방식은 ****겉보기에는 동일한 문자열 값을 가지지만****, 내부 메모리 구조, 생성 방식, 비교 결과, 성능 등에서 중요한 차이를 가진다.
---
## 2. 메모리 구조 차이
### 2.1 리터럴 방식 (`String s = "hello"`)
- 문자열 리터럴은 ****String Constant Pool****이라는 특별한 메모리 영역에 저장된다.
- 동일한 리터럴이 여러 번 사용되더라도 ****중복 없이 하나의 객체로 공유****됨.
- JVM이 ****자동 최적화****해 메모리 사용이 매우 효율적이다.
#### 예시
```java
String a = "hello";
String b = "hello";
System.out.println(a == b); // true (같은 객체 참조)
System.out.println(a.equals(b)); // true (내용도 동일)
```
→ ****같은 상수 풀 객체****를 참조하고 있기 때문에 `a == b`는 `true`.
---
### 2.2 new 연산자 방식 (`String s = new String("hello")`)
- `new String()`은 무조건 Heap 메모리에 ****새로운 객체를 생성****한다.
- 내부적으로 리터럴 `"hello"`를 참조하더라도, 그 값을 복제한 ****별도 인스턴스****가 생성됨.
#### 예시
```java
String a = "hello";
String b = new String("hello");
System.out.println(a == b); // false (다른 참조)
System.out.println(a.equals(b)); // true (내용은 같음)
```
→ `==` 결과는 `false`, `.equals()`는 `true`
---
## 3. 객체 비교 방식
### 3.1 `==` 연산자 (참조 비교)
- 두 객체의 ****참조 주소값을 비교****함
- ****리터럴 방식****끼리는 상수 풀 공유로 `true`일 수 있음
- `new`로 생성한 객체는 항상 `false`
### 3.2 `.equals()` 메서드 (값 비교)
- 두 문자열의 ****내용이 같은지**** 비교함
- 방식과 무관하게, ****내용이 같으면 항상** `true`**
```java
String s1 = "test";
String s2 = new String("test");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true
```
---
## 4. 성능 및 메모리 효율
항목
| 리터럴 방식 (
`"hello"`)
| new 방식 (
`new String("hello")`)
|
---|
메모리 위치
| Constant Pool (Method Area)
| Heap 영역
|
객체 중복 여부
| 없음 (공유됨)
| 항상 새 객체 생성
|
`==`
비교 결과
| true (동일 참조)
| false (서로 다른 참조)
|
`.equals()`
결과
| true
| true
|
메모리 효율
| 높음
| 낮음
|
성능
| 빠름
| 느림 (GC 대상 증가)
|
GC 부담
| 낮음
| 높음
|
사용 권장 여부
| ✅ 일반적으로 권장
| ❌ 특별한 경우에만 사용
|
---
## 5. 실제 사용 시 차이
### 5.1 리터럴 방식 – 일반적으로 권장
- ****정적 값****, ****설정 상수****, ****조건 분기**** 등에 적합
- 성능과 메모리 효율이 우수함
```java
if (userRole.equals("ADMIN")) {
// 권한 체크
}
```
### 5.2 new 방식 – 특수 목적용
- 동일한 문자열이더라도 ****서로 다른 객체를 명시적으로 생성****할 때
- 예: ****문자열 캐시 우회****, ****디버깅용 비교****, ****참조를 강제로 분리해야 할 경우****
- 필요하다면 `.intern()` 메서드를 사용해 수동으로 상수 풀 등록 가능
```java
String s = new String("hello").intern(); // Constant Pool 등록
```
---
## 6. 정리: 리터럴 vs new String()
비교 항목
| 리터럴 방식 (
`"hello"`)
| new 방식 (
`new String("hello")`)
|
---|
저장 위치
| String Constant Pool
| Heap 메모리
|
객체 공유 여부
| ✅ 공유됨 (중복 방지)
| ❌ 매번 새 객체 생성
|
`==`
비교 결과
| true
| false
|
`.equals()`
결과
| true
| true
|
성능
| 빠름
| 느림
|
메모리 효율
| 높음
| 낮음
|
GC 부담
| 낮음
| 높음
|
사용 추천 여부
| ✅ 일반적 상황에서 적극 권장
| ⚠️ 특별한 목적이 없으면 지양
|
---
## 7. 결론
- 문자열은 ****리터럴 방식으로 생성하는 것이 가장 효율적****이다.
- `new String()` 방식은 ****불필요한 Heap 객체 생성****으로 인해 성능과 메모리 측면에서 불리하다.
- 문자열 비교 시에는 항상 `==`이 아닌 **`.equals()`** 를 사용할 것.
- ****고급 최적화****가 필요한 경우에는 `.intern()`으로 Constant Pool을 수동 활용할 수 있다.
---
이 정리는 `Java` 메모리 구조, 성능 최적화, 참조와 객체 비교에 대해 정확한 이해를 돕기 위한 위키 스타일
자바에서 문자열은 두 가지 방법으로 생성할 수 있다.
String str = "hello";와 String str = new String("hello"); 두 가지 방식은 같아 보이지만, 작동 방식, 메모리 구조, 성능, 객체 비교 등 여러 측면에서 차이가 난다.
```java
String s1 = "hello"; // 리터럴 방식
String s2 = new String("hello"); // new 연산자 사용
```
두 방식은 겉보기에는 같은 값을 가지지만, 메모리 처리, 비교 방법, 성능 등의 측면에서 분명한 차이가 존재한다.
### 1. 메모리 구조 차이
#### 1.1 리터럴 방식: String s1 = "hello";
문자열 리터럴은 String Constant Pool에 저장된다.
JVM은 동일한 문자열 리터럴이 여러 번 등장하더라도 중복을 제거하여 하나의 객체만 저장한다.
메모리 효율이 높고, 비교 연산 시 빠르다.
📌 예시
```java
String a = "hello";
String b = "hello";
System.out.println(a == b); // true (같은 상수 풀 객체)
```
#### 1.2 new 연산자 방식: String s2 = new String("hello");
new 키워드를 사용하면 Heap에 새로운 객체가 강제로 생성된다.
비록 내부적으로 "hello"라는 리터럴이 사용되더라도, Constant Pool의 객체를 복제한 별도 인스턴스가 Heap에 만들어진다.
따라서 리터럴과는 다른 참조값을 가진다.
📌 예시
```java
String a = "hello";
String b = new String("hello");
System.out.println(a == b); // false (주소 다름)
System.out.println(a.equals(b)); // true (값 같음)
```
### 2. 객체 비교 (== vs equals())
#### 2.1 == (참조 비교)
리터럴 방식은 JVM이 Constant Pool을 공유하므로 == 결과가 true일 수 있다.
new 키워드는 항상 새로운 객체를 생성하므로 == 비교 시 false가 된다.
#### 2.2 .equals() (내용 비교)
두 방식 모두 문자열 내용을 같게 만들면 .equals()는 항상 true를 반환한다.
문자열 비교에서는 항상 .equals()를 사용하는 것이 안전하다.
### 3. 성능 및 메모리 효율
3.1 리터럴 방식
- 런타임 시 상수 풀을 이용하므로 메모리 사용이 효율적이다.
- JVM이 자동으로 중복 문자열을 제거해주므로 불필요한 객체 생성을 방지할 수 있다.
- 가장 선호되는 방식.
3.2 new 방식
- new String()을 사용할 경우 매번 객체가 새로 만들어지므로 메모리 낭비 가능성이 있다.
- GC(Garbage Collector) 부담 증가 → 성능 저하로 이어질 수 있음.
- 특별한 이유(예: 강제로 다른 참조를 만들어야 할 필요)가 없다면 지양하는 것이 좋다
### 4. 실제 사용 시 차이점
4.1 리터럴 방식의 사용 예
- 상수 정의, 비교가 필요한 경우
- 조건 분기, 설정 값 체크 등에서 성능 이점 있음.
```
if (userRole.equals("ADMIN")) { ... }
```
4.2 new 방식의 사용 예
- 객체 생성을 명시적으로 컨트롤해야 하는 특수한 경우
- 외부 API나 라이브러리에서 intern() 메서드를 사용하여 상수 풀로 다시 보낼 수도 있음
```
String s = new String("hello").intern(); // 풀로 보냄
```
### 5. 정리
| 리터럴 방식 (`"hello"`)
| new 방식 (`new String("hello")`)
|
---|
메모리 위치
| Constant Pool (Method Area)
| Heap 영역
|
객체 중복 여부
| 없음 (공유됨)
| 항상 새 객체 생성
|
`== ` 비교 결과
| true (같은 참조)
| false (다른 객체)
|
`.equals()` 결과
| true
| true
|
메모리 효율
| 높음
| 낮음
|
성능
| 빠름
| 느림
|
GC 부담
| 낮음
| 높음
|
사용 권장 여부
| 일반적으로 권장
| 특별한 경우에만 사용
|
---
### 6. 결론
- 문자열을 선언할 때는 특별한 이유가 없다면 "hello"와 같은 리터럴 방식을 사용하는 것이 가장 효율적이다.
- new String()은 불필요한 객체 생성을 유발하며, 메모리와 성능 측면에서 손해를 볼 수 있다.
- 문자열 비교 시에는 항상 ==가 아닌 .equals()를 사용할 것.
- 최적화를 원할 경우 intern()을 활용해 상수 풀을 직접 사용할 수도 있다.
---