[Java] equals()과 == 차이점, String Constant Pool(상수 풀)
자바에서 String의 값을 비교할때 equals()를 쓰시나요 ==을 쓰시나요?
보통 산술연산자에서 값을 비교할때는 ==을 하는데요
인텔리제이에서 String의 값을 비교할때 ==을 쓰면 아래와 같은 메세지를 확인할 수 있어요
option+enter를 눌러주면 ==을 equals()로 바꾸라고 조언을 해줍니다.
==와 equals()는 어떤 차이가 있는걸까요?
==은 비교를 위한 연산자, equals()는 비교를 위한 메소드로 둘다 비교를 하는 목적은 맞습니다. ⭕️
하지만 비교를 하는 내용 ❗️알맹이❗️가 다릅니다. ❌
-
==은 주소 값을 비교합니다.
-
equals는 주소 안에 들어있는 값을 비교합니다.
그렇다면,,,
-
new String("Java")와 new String("Java")는 같을까요? 🤔
-
new String("Java")와 "Java"는 같을까요? 🤔
-
"Java"와 "Java"는 같을까요? 🤔
하나씩 살펴보겠습니다.
1. new String("Java")와 new String("Java")
결과: s1과 s2가 같지 않습니다.
2. new String("Java")와 "Java"
결과: s1과 s2가 같지 않습니다.
3. "Java"와 "Java"
결과: s1과 s2가 같습니다.
왜 이런 결과가 나오는걸까요?
new 연산자로 String 객체를 생성하면 JVM에서 Heap 영역에 String 객체를 생성하게 됩니다.
그렇기 때문에 s1을 Heap 메모리에 생성하고, s2를 또 Heap 메모리에 생성하고 이 둘은 다른 객체가 되는거죠
그럼 세번째 결과가 같은 이유는 무엇일까요?
new 연산자가 아닌 리터럴("")로 String 객체를 생성하면 JVM은 우선 String Constant Pool 영역을 방문하게 됩니다. 거기서 같은 값을 가진 String 객체를 찾으면 그 객체의 주소 값을 반환하여 참조하게 됩니다. 찾지 못하면 String Constant Pool에 해당 값을 가진 String 객체를 생성하고 그 주소 값을 반환하게 됩니다.
String Constant Pool 영역은 Heap 영역 내부에서 String 객체를 위해 별도로 관리하는 저장소입니다!
리터럴로 s1을 생성할때 String Constant Pool에 "Java"라는 값을 가진 String 객체가 생성되었고, s2 또한 리터럴로 생성되었기 때문에 String constant pool에 방문해보았더니 s1을 생성할때 만들어둔 "Java"라는 값을 가진 String 객체가 있었던거죠!
결과적으로 s1과 s2는 같은 객체를 참조하고 있는 것입니다.
그림으로 표현해보았는데요 이해에 도움이 되면 좋겠습니다!
그렇기 때문에 같은 "Java"라는 값을 가지는 s1과 s2가 객체를 생성하는 방식에 따라 == 비교의 결과가 true일수도 false일수도 있게 되는 것입니다.
하지만 equals는 주소 안에 들어있는 값을 비교한다고 하였죠
결과: s1과 s2가 같습니다.
s1과 s2는 다른 주소 값을 가진 분명히 다른 객체이지만 equals 메소드는 각각의 주소 안에 들어있는 값을 비교하기 때문에 == 비교의 결과와 달리 's1과 s2가 같습니다.'가 나오게 되는 것입니다.
그러므로 일반적인 String 비교에서는 ==이 아닌 equals()를 쓰는게 목적에 맞겠죠?
리터럴로 선언할 경우에 내부적으로 어떤 동작이 일어나는걸까요?
String의 intern() 메소드를 호출하게 됩니다.
intern() 메소드는 무엇일까요?
앞에서
new 연산자가 아닌 리터럴("")로 String 객체를 생성하면 JVM은 우선 String constant pool 영역을 방문하게 됩니다. 거기서 같은 값을 가진 String 객체를 찾으면 그 객체의 주소 값을 반환하여 참조하게 됩니다. 찾지 못하면 String Constant Pool에 해당 값을 가진 String 객체를 생성하고 그 주소 값을 반환하게 됩니다.
라고 하였는데요.
이 행위를 수행하는 메소드입니다.
new 연산자로 생성한 String 객체에 intern() 함수를 호출하면 리터럴로 생성했을 때와 같이 위와 같은 행위가 수행되겠죠?
결과: s1과 s2가 같습니다.
그래서 intern()을 붙이기 전엔 s1은 Heap에 생성된 객체이고 s2는 String Constant Pool에 생성된 객체로 서로 다른 객체이기 때문에 결과가 's1과 s2가 같지 않습니다.' 였는데
s1에 intern()을 수행했기 때문에 String Constant Pool에 객체가 생성되게 되고, 그 후 s2는 리터럴로 생성되었기 때문에 String Constant Pool을 방문하여 이전에 s1에서 생성해두었던 "Java" 값을 가진 String 객체를 발견하게 되어 두 객체가 완전히 같은 것입니다.
- String Constant Pool이 무엇인지
- ==와 equals()의 차이는 무엇인지
- intern()은 무슨 메소드인지
모두 잘 이해가셨나요? 😊