결론부터 말하면 다음과 같습니다.
- 기본형 데이터 비교는 ==를 사용하자.
- 문자열 비교는 equals를 사용하자.
- 하지만 equals 사용 시 NullPointerException이 발생할 수 있기 때문에 "문자열1".equals( "문자열2" )처럼 사용할 때 반드시 "문자열1"은 Null 데이터가 들어올 수 없는 방식을 사용해야 한다.
- 신경 쓰고 싶지 않다면 Object.eqauls( "문자열1", "문자열2" )를 사용하자.
이 아래부터는 문자열 비교에 대해 조금 더 자세히 알아보겠습니다.
데이터를 비교할 때 많이 사용하는 방법으로 3가지가 있습니다.
- "문자열1" == "문자열2"
- "문자열1".equals( "문자열2" )
- Object.eqauls( "문자열1", "문자열2" )
각각 다른 결과를 반환하기 때문에 정확하게 알고 사용하는 것이 중요하다고 생각합니다.
데이터 비교와 관련해서 먼저 알아야 할 사항은 자바 데이터 타입이라고 생각합니다.(데이터 타입 설명은 생략합니다.)
그래서 데이터 비교를 위해 알아야 할 사실은 문자열(String)의 데이터 타입은 기본형 데이터 타입이 아니라는 점입니다.
이 점을 명확하게 알면 왜 방법에 따라 다른 결과가 반환되는지 이해하는데 도움이 될 것이라 생각합니다.
먼저 두 개의 문자열을 비교하면 boolean type을 반환하는 것이 문자열 비교의 핵심입니다.
간단한 예와 함께 확인해보겠습니다.
int a = 111;
int b = a;
int c = 123;
// a = b : true
System.out.println("a == b : " + (a == b));
// a == c : false
System.out.println("a == c : " + (a == c));
// X
System.out.println("a.equals(b) : " + a.equals(b));
System.out.println("a.equals(c) : " + a.equals(c));
// Objects.equals(a,b) : true
System.out.println("Objects.equals(a,b) : " + Objects.equals(a, b));
// Objects.equals(a,c) : false
System.out.println("Objects.equals(a,c) : " + Objects.equals(a, c));
자바의 기본형 데이터 타입 int 비교에 ==을 사용해서 데이터를 비교합니다.
그 이유는 == 연산자는 주소 값을 비교하는 연산자입니다.
간단하게 설명하면 기본형은 Constant Pool에 있는 특정 상수를 참조합니다.
그래서 ==을 사용해도 예상한 결과를 얻을 수 있습니다.
그리고 기본형은 최상위 클래스인 Object에 포함되어 있지 않기 때문에 equals를 사용할 수 없습니다.
+ 만약 기본형 타입 비교를 ==이 아닌 equals를 사용하고 싶다면 Wrapper클래스를 사용하면 equals를 사용할 수 있습니다.
++ null 처리를 하려면 반드시 Wrapper클래스를 사용해야 합니다.
다시 문자열 비교를 이야기하면 문자열은 기본형 타입이 아닌 참조형 타입입니다.
기본형 변수는 변수 자체가 데이터라면 참조형 변수는 참조형 안에 데이터가 담겨있는 방식입니다.
그래서 참조형 타입 비교에 주소 값을 비교하는 ==을 사용하면 변수의 데이터는 같아도 변수 주소는 다르기 때문에 예상과 다른 결과를 얻습니다.
AAA aaa = new AAA();
// 모든 변수의 값은 123으로 통일
String a = "123"; // 123
String b = a; // 123
String c = new String("123"); // 123
String aa = aaa.getAa(); // 123
// 1) a == b : true
System.out.println("a == b : " + (a == b));
// 2) a == c : false
System.out.println("a == c : " + (a == c));
// 3) a == aa : true
System.out.println("a == aa : " + (a == aa));
private class AAA {
private String aa = "123";
public String getAa() {
return aa;
}
}
- a와 b는 같은 주소 값을 가지고 있습니다. 그래서 a와 b 변수를 비교하게 되면 true 값이 반환됩니다.
- 하지만 c는 새로운 객체를 생성했기 때문에 변수 a와는 다른 주소를 가지고 있습니다. 그래서 a와 c를 비교하면 false 값이 반환됩니다.
- aa의 경우도 동일합니다. 다른 객체로부터 가져온 값이기 때문에 다른 주소를 가지고 있기 때문에 false를 반환합니다.
그렇다면 우리는 어떻게 문자열을 비교해야 할까요?
그럴 때 사용하는 게 바로 equals라는 메서드입니다.
AAA aaa = new AAA();
// 모든 변수의 값은 123으로 통일 ( '==' 과 동일한 데이터 )
String a = "123"; // 123
String b = a; // 123
String c = new String("123"); // 123
String aa = aaa.getAa(); // 123
// a.equals(b) : true
System.out.println("a.equals(b) : " + a.equals(b));
// a.equals(c) : true
System.out.println("a.equals(c) : " + a.equals(c));
// a.equals(aa) : true
System.out.println("a.equals(aa) : " + a.equals(aa));
private class AAA {
private String aa = "123";
public String getAa() {
return aa;
}
}
equals를 사용하면 ==를 사용할 때와는 다른 결과가 나옵니다.
equals 결과는 전부 true입니다.
그 이유는 equals는 객체의 값을 비교하기 때문입니다.
그래서 문자열 비교를 할 때는 최소한 equals를 사용해야 합니다.
하지만 equals를 사용하면 NullPointerException이 발생할 수 있습니다.
NullPointerException을 방지하기 위한 방법으로는 2가지 방법이 있습니다.
AAA aaa = new AAA();
String a = "123"; // 123
String b = aaa.getBb(); // null
// 1) a.equals(b) : false
System.out.println("a.equals(b) : " + a.equals(b));
// 2) NullPointerException 발생
System.out.println("b.equals(a) : " + b.equals(a));
// 3) Objects.equals(a,b) : false
System.out.println("Objects.equals(a,b) : " + Objects.equals(a, b));
// 4) Objects.equals(b,a) : false
System.out.println("Objects.equals(b,a) : " + Objects.equals(b, a));
private class AAA {
private String aa = "123";
private String bb;
public String getAa() { return aa; }
public String getBb() { return bb; }
}
- 변수에 담긴 데이터를 비교하면 a : 123 / b : null 이기 때문에 false라는 결과가 나옵니다.
- 하지만 이번엔 null과 다른 데이터를 비교하기 때문에 NullPointerException 발생
- Objects.equals를 사용하게 되면 1)과 2)처럼 순서가 달라진다고 해서 NullPointerException이 발생하지 않고 false라는 결과가 나옵니다.
마지막으로 추가사항입니다.
// enum 사용
String a = "123";
// true
System.out.println("a == BBB.abc.getValue() : " + (a == BBB.abc.getValue()));
System.out.println("a.equals(BBB.abc.getValue()) : " + a.equals(BBB.abc.getValue()));
String aaa = "aaa";
String AAA = "AAA";
// false
System.out.println("aaa.equals(AAA) : " + aaa.equals(AAA));
// true
System.out.println("aaa.equals(AAA) : " + aaa.equalsIgnoreCase(AAA));
private enum BBB {
abc("123");
private String value;
BBB(String value) { this.value = value; }
public String getValue() { return value; }
}
Enum 결과 String과 String 데이터를 ==로 비교해도 true라는 결과가 나옵니다.
하지만 가능하면 문자열 비교는 equals를 사용하는 것이 좋다고 생각합니다.
그리고 equals는 대/소문자를 구분하기 때문에 대/소문자 구분 없이 비교하려면 equalsIgnoreCase를 사용하면 됩니다.
마지막으로 정리하면 이렇습니다.
== 은 주소 값을 비교하는 연산자로 보통 기본형 타입 비교에 사용 (Call By Reference)
equals는 객체의 내용을 비교하는 연산자로 참조형 타입 비교에 사용 ( Call by Value )
도움이 되었다면 좋아요만 눌러주세요. 감사합니다.
'백엔드 > JAVA' 카테고리의 다른 글
[JAVA] 문자열 포함 여부 확인 메소드(startsWith, endsWith, contains) (0) | 2022.12.21 |
---|---|
[JAVA] 문자열과 관련된 메소드 (2) | 2022.10.18 |
[JAVA] 객체 자료형 이해하기 (0) | 2021.12.25 |
추상 클래스, 내부 클래스, 인터페이스 (0) | 2021.08.31 |
제어자 (0) | 2021.08.31 |
최근댓글