어떠한 값이나 객체가 동등한지 비교할 때 우리는 == 연산자 또는 equals() 함수를 사용한다.
먼저 이 둘의 차이점을 알아보자.
1️⃣ == 연산자
- 동등 비교 연산자로, boolean 타입인 true / false 를 반환한다.
- 만약 두 피연산자의 값이 같다면 true, 다르면 false 를 반환한다.
- 두 객체의 메모리 공간이 같은지 확인하는 참조 비교 방식이다.
- 모든 타입에 적용할 수 있다.
public class Main{
public static void main(String[] args){
{
System.out.println(1 == 1); //true
System.out.println(2.3 == 2.2); //false
System.out.println('a' == 'b'); //false
System.out.println('A' == 65); //true
System.out.println(3 == 3.0); //true
}
}
중요한 점은 연산을 수행하기 전에 피연산자의 타입을 일치시켜야 한다는 것이다.
예시와 같이 'A' == 65 는 'A' 의 정수 타입인 65로 변환되어 65 == 65로 비교되기 때문에 true 가 나오는 것이다.
또한 3 == 3.0 도 int 타입인 3이 double 타입으로 자동 형변환되어 3.0 == 3.0 의 결과인 true 가 나온다.
그러나 소수를 다룰 때엔 주의해야한다. 예를 들어 0.1==0.1f 는 false 를 반환한다.
java 에선 소수를 이진 포맷의 가수를 사용한다고 알고 있다. 이 부동소수점 타입은 0.1 이라는 숫자를 정확하게 표현할 수 없기 때문에 근사값으로 계산되어 같은 값이 나오지 않는 것이다.
이 때는 모두 float 으로 강제 형변환을 한 후 연산을 하거나 int 로 변환하여 연산하면 문제가 해결된다.
2️⃣ String 에서 == 연산자
String 에서의 == 연산자 사용은 조금 다르다.
위에서 == 는 참조 방식이라고 하였다. 따라서 객체인 String 타입을 비교할 때엔 주의해야한다.
public class Main{
public static void main(String[] args){
String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");
System.out.println(str1 == str2); //true
System.out.println(str1 == str3); //false
}
}
언뜻 보기에 str1, str2, str3 모두 "hello" 라는 값을 가지니 == 연산의 결과가 true 라고 생각할 수 있다.
그러나 java 는 문자열 리터럴이 동일하다면 동일한 String 객체를 참조하도록 되어 있다.
따라서 str1 과 str2 는 동일한 객체의 메모리 주소를 갖는다.
반면 str3 는 new 연산자를 통해 새로운 객체를 참조하기 때문에 == 연산의 결과는 false 이다.
그렇다면 String 객체의 값을 비교하기 위해선 어떻게 해야할까?
3️⃣ String.equals()
단순히 문자열의 값을 비교할 땐 equals 메소드를 사용한다.
이는 == 연산자와 다르게 주소가 달라도 해당 문자열만 같다면 true 를 반환한다.
만약 str1 과 str2 의 내용이 같은지 확인하려면 다음과 같이 작성하면 된다.
public class Main{
public static void main(String[] args){
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2); //false
System.out.println(str1.equals(str2)); //true
}
}
String 의 equals 는 java 의 최상위 클래스인 'Object' 의 equals 메소드를 오버라이딩하여 사용한다.
이는 해당 객체가 생성된 주소를 비교하기 때문에 재정의하여 사용되는 것이다.
- 객체를 비교하는 메소드로, boolean 타입인 true / false 를 반환한다.
- 만약 두 객체의 값이 같다면 true, 다르다면 false 를 반환한다.
- 두 객체의 내용을 비교하는 내용 비교 방식이다.
- 기본 타입에선 적용할 수 없다.
4️⃣ 사용자 정의 비교
HashSet 은 Java Collection 의 한 종류로, Set 인터페이스의 구현 클래스이다.
이는 객체들을 순서 없이 저장하고 동일한 객체는 중복 저장하지 않는다.
그렇다면 동일한 객체인지 어떻게 비교하는지 알아보자.
HashSet 은 객체를 저장하기 전에 객체의 hashCode() 메소드를 통해 해시코드를 얻는다.
그리고 이미 저장된 해시코드와 비교하여 동일한 해시코드가 있다면 equals() 메소드를 통해 두 객체를 비교한다.
여기서 true 가 나오면 동일 객체로 판단, 중복 저장을 하지 않는다.
따라서 equals 메소드와 hashCode 메소드를 오버라이딩하여 두 객체를 비교할 수 있다.
public class Member{
public String name;
public int age;
public Member(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj){
if(obj instanceof Member) {
Member member = (Member)obj;
return member.name.equals(name) && member.age == age;
} else {
return false;
}
}
@Override
public int hashCode() {
return name.hashCode() + age;
}
}