
우리가 코드를 짜다 보면 if 문에서 == 를 많이 사용합니다. String 변수의 값을 판단할 때도 으레 == 를 사용하는 경우가 있습니다.
String language = "자바";
if(language == "자바") {
System.out.println("자바 언어 입니다.");
} else {
System.out.println("자바가 아닌 다른 언어 입니다.");
}
위와 같은 코드가 있다고 해봅시다. 하지만 아래와 같은 메세지가 뜨는데요

int 나 boolean 과 같은 일반적인 데이터 타입의 비교를 할 때는 저런 메세지가 뜨지 않는데 String 처럼 class 값을 비교할 때는 저런 비교 메세지가 뜹니다. equals()와 ==는 무엇이 다르기에 equals() 로 바꾸라고 제안하는걸까요?
한번 알아보도록 하겠습니다.
우선, String 변수를 생성하는 방법부터 설명해보도록 하겠습니다. String 변수를 생성할 때는 두 가지 방법이 있습니다.
String str = “java”’; //리터럴
String str = new String(java); //new 연산자
리터럴을 사용하기 되면 string constant pool 이라는 영역에 존재하기 되고 new를 통해 생성하면 Heap 영역에 존재하게 됩니다. String을 리터럴로 선언한 경우 내부적으로 String의 intern() 메서드가 호출되고, intern() 메서드는 주어진 문자열이 string constant pool에 존재하는지 검색하고 있다면 그 주소값을 반환, 없다면 string constant pool에 넣고 새로운 주소값을 반환합니다.
String a = "apple";
String b = new String("apple");
String c = "apple";
String d = new String("apple");
위와 같이 코드를 구현했다고 해봅시다. a와 c는 리터럴로, b와 d는 new 연산자를 사용했습니다. 리터럴 방식인 String a의 apple 은 string pool 에 존재하지 않으므로 pool에 새로 넣어집니다. 그리고 리터럴 방식으로 생성된 c는 pool에 이미 “apple”이 존재하므로 이미 pool에 존재하는 주소값을 갖게됩니다. 즉, a와 c는 같은 주소값을 갖게 됩니다. 그리고 b와 d는 new 연산자로 생성되었기 때문에 heap 에 각각 독립적인 주소값을 갖게 됩니다. 그림으로 보면 아래와 같습니다.

위와 같은 경우를 보면, 우리는 총 2가지를 비교할 수 있음을 유추할 수 있습니다. 바로 (1)주소값 과 (2)실제 데이터 값 입니다. 데이터 값은 a,b,c,d 모두 “apple” 로 같다고 비교할 수 있습니다. 하지만 주소 값을 비교할 때, a와 c는 같지만 a,c 와 b, d는 서로 다릅니다. 우리는 이렇게 2가지 비교를 각각 할 수 있어야 합니다.
==equals()== 연산자와 equals() 메소드의 차이점은 “주소값 비교” 를 하는지, “실제 값 비교” 하는지 여부 입니다. 기본 원시 타입인 int, boolean, char 형들은 call by value 형태로 기본적으로 대상에 주소값을 가지지 않습니다. 바로 값이 저장이 되죠. 그렇기 때문에 단순히 == 를 사용하여 비교해도 됩니다. 비교할 대상이 1가지이기 때문이죠.
하지만 String 은 원시타입이 아닌 클래스타입입니다. 클래스는 기본적으로 call by reference 형태로 생성 시 주소값이 부여됩니다. 그렇기 때문에 String 과 같이 class 타입을 선언 했을 때는 같은 값을 부여하더라도 서로간의 주소값이 달라 단순히 == 만 사용하면 사용자가 원하는 결과를 얻지 못할 수도 있습니다.
String value1 = "A";
String value2 = new String("A");
if(value1 == value2) {
System.out.println("서로 같은 주소값을 가집니다.");
} else {
System.out.println("서로 다른 주소값을 가집니다.");
}
결과 >>> 서로 다른 주소값을 가집니다.
== 연산자의 경우, 참조 타입 변수들 간의 연산은 동일한 객체를 참조하는지 여부를 판단합니다. 즉, 객체의 주소값을 비교하게 되는데 value1은 리터럴 방법을 통해 string pool에 생성이 되고, value2는 new 연산자를 통해 heap 영역의 다른 메모리로 생성이 되었으므로 다르다는 결과가 나오게 됩니다.
String value1 = "A";
String value2 = new String("A");
if(value1.equals(value2)) {
System.out.println("서로 같은 값을 가집니다.");
} else {
System.out.println("서로 다른 값을 가집니다.");
}
결과 >>> 서로 같은 값을 가집니다.
String 클래스 안에 있는 equals 라는 메서드를 사용하면 주소 값이 아닌 데이터 값을 비교하는 것을 볼 수 있습니다. 어떻게 생성하느냐에 따라 결과가 달라지지 않고 정확한 비교를 할 수 있습니다.
== 와 equals() 의 차이점에 대해서 알아봤습니다. 차이점을 알아보는 과정에서 String 타입의 생성 방식에 대해서도 배웠습니다.
Class 타입의 객체를 비교할 때, 주소값을 비교할지 데이터 값을 비교할지 사용자의 목적에 따라 적절히 == 와 equals() 를 사용하면 됩니다.