본문 바로가기

자바/정리

(JAVA) Object 클래스 equals()

우리는 클래스와 메서드에 대해서 이미 학습을 하였다. 간단히 이들에 대해서 다시 한번 생각해보자.

 

자바에서 기본으로 제공하는 클래스들이 있었다 예를들어 math,System 혹은 Arrays 같은 클래스들 말이다.

 

해당 클래스들 안에는 메서드들이 정의되어 있다. 예를들어 math.abs()를 사용하면 math 클래스 내부에 있는 abs() 사용하여 절대값을 출력하게 되며, math.random()을 사용하면 랜덤 값을 얻을수 있었다.

 

이렇게 수많은 클래스들이 사용자의 편의를 위해 미리 정의되어 있으며 추가로 지금 까지 우리가 필요하면 클래스를 직접 정의해서 사용하곤 하였다.

 

이야기가 다소 길어졌지만 사실 모든 클래스는 숨김처리 되어있지만 Object 라는 클래스를 extends Object 하여 이미 상속받고 있다.(부모를 넘어선 조상... 그래서 부모에게 자식이 있어도 자식이 또 상속 받아서 Object를 가지게 된다.)

 

다들 클래스에서 메서드를 불러올때 반드시 위의 메서드들을 보았을 것이다.

사진 처럼 나는 Main 클래스에 아무것도 입력하지 않았는데 메서드들이 나오고 있다. 이유는 Main 클래스가 Object 클래스를 상속받고 있기 때문에 Object 메서드들을 가져오고 있는 것이다.

 

 

이처럼 Object 클래스는 다양한 메서드들을 가지고 있는데 이중에 자주 쓰이는 메서드는

 

1.equals()

2.toString()

3.hashCode()

 

이번에는 위의 3가지 메서드을 알아볼 것이다.

 

equals()

equal를 그냥 읽어보면 동등한 이라는 뜻이 있다. 실제로 그렇게 사용된다. 하지만 우리는

 

==

연산자 로서 이걸 본적이 있고 사용법도 알것이다. 결론부터 말하면 그냥 사용 하게 된다면 같은 결과를 출력 하게 된다.

 

class dog {
    String crying;
    dog(String crying) {
        this.crying = crying;
        System.out.println(crying);
    }
}
class Main {
    public static void main(String[] args) {

        dog poodle = new dog("멍멍!");
        dog toy_poodle = poodle;
        dog maltese = new dog("멍멍!");
        dog chiwawa = new dog("으르렁..");

        System.out.println(poodle == maltese);  // F
        System.out.println(poodle.equals(maltese)); //F
        System.out.println(poodle == toy_poodle); //T
        System.out.println(poodle.equals(toy_poodle)); //T
        System.out.println(maltese == chiwawa); //F
        System.out.println(maltese.equals(chiwawa)); //F
    }
}

 

출력 결과는 다음과 같다.

멍멍!
멍멍!
으르렁..
false
false
true
true
false
false

 

 

앞서, 이전에 enum 게시글에서 자바는 타입과 값을 같이 비교 한다고 하였다. 하지만 지금 비교하는 것은 객체인데 이들은 주소 값을 비교 당하게 된다. 확실히 이해하기 위해 작은 예제를 추가 하였다.

String poodle2 = "멍멍!";
String poodle3 = "멍멍!";
System.out.print(poodle2 == poodle3);

결과는 true일까 false 일까?

각 변수들이 String 타입에 멍멍! 이라는 동일한 타입과 값을 가지고 있다.

당연히 true가 나온다. 물론 한쪽이 왈왈!로 값을 바꾸게 되면 false가 출력이 될것이다. 혹은 String을 다른것으로 바꾸게 되어도 형변환 에러가 뜰것이다.

 

 

 

이제 equals()를 이어서 살펴 보도록 하겠다.

 

푸들, 토이푸들, 말티즈, 치와와라는 객체를 생성하였고 이들은 생성자를 통해  멍멍 이라는 문자열을 출력 하도록 만들었다.

 

비교 연산자와 equals() 가 같은 결과를 출력 하는것을 알수가 있다.

 

System.out.println(poodle == maltese);  // F
System.out.println(poodle.equals(maltese)); //F

위에서 이들은 주소 값을 비교 당한다고 하였다. 객체들은 생성이 되면 각자 다른 주소값을 가지게 되는데 메모리 저장 위치라고 생각하면 좋다(내방에는 나만 들어감) 하여 false를 출력하게 된다.

 

하지만

dog toy_poodle = poodle;
System.out.println(poodle == toy_poodle); //T
System.out.println(poodle.equals(toy_poodle)); //T

사용자가 토이푸들이 푸들과 같은 객체라고 선언해 버리면 이들은 같은 주소값을 가지게 된다. 하여 true를 출력하게 된다.

 

이렇게 간단하게 주소값만 비교하는 것을 얕은 비교(shallow comparison) 라고 한다.

 

 

얕은 비교가 있다면 깊은 비교도 있지 않겠는가?

 

 

객체들은 값을 가질수 있다는것은 다들 알고 있을 것이다. 푸들이 멍멍! 이라는 값을 가지고 있고 치와와가 으르렁.. 이라는  값을 가지고 있는 것 처럼 말이다. 그 멍멍! 과 으르렁.. 즉 객체가 가진 값을 비교 하는 것을 깊은 비교(deep comparison) 라고 한다.

 

잘 생각해보자 == 이라는 연산자랑 equals랑 같은 기능을 한다면 왜 만들었을까? 기능은 같아도 equals는 메서드 이다.

즉, 메서드 오버라이딩을 통해 메서드를 재설정하여 우리가 원하는 깊은 비교를 할수 있게 된다.

 

 

class dog {
    String crying;
    dog(String crying) {
        this.crying = crying;
        System.out.println(crying);
    }
    public boolean equals(Object obj){
        dog d = (dog)obj;
        return this.crying == d.crying;
    }
}

equals를 오버라이딩 하여 객체를 받는 코드를 만들었다. 오버라이딩이면 변경한것인데 변경전은

 

public boolean equals(Object obj){
    return this == obj;
}

이런 구조를 가지고 있다.

 

여기에 부모인 Object에서 만들어진 obj는 crying 이라는 변수가 없기에 강제로 타입을 맞춰서 형변환을 해줘야 한다.

그래서 dog d = (dog)obj 를 입력 하였다. 그 뒤에 객체의 값을 비교 하게 되는데 실행하면

 

System.out.println(poodle == maltese);  // F
System.out.println(poodle.equals(maltese)); //T

푸들과 말티즈가 같이 멍멍! 이라는 값을 가지고 있기에 true를 출력하게 된다.

 

우리가 알수 있는 것은 깊은 비교를 하게 되면 푸들과 말티즈가 동일 한것이 아닌 서로 동등하다 라고 표현할수 있다.

 

 

글이 너무 길어져서 toString()과 hashcode()는 다음 게시물에서 설명하겠다.

'자바 > 정리' 카테고리의 다른 글

(JAVA)제네릭  (0) 2022.12.13
(JAVA) Object 클래스 toSting(), hashcode()  (0) 2022.12.08
(JAVA) 예외  (1) 2022.11.30
(JAVA)다형성  (0) 2022.11.25
(JAVA)인터페이스  (0) 2022.11.21