JAVA Override

동제동이·2023년 3월 25일
1

JAVA

목록 보기
5/5
post-thumbnail

왜 equals(), toString(), hashCode()를 오버라이딩 하는 걸까??

내가 생성한 클래스들은 Object를 최상위 클래스로 상속받고 있다.
그래서 내 클래스에서도 Object 클래스의 메서드를 사용할 수 있다.

Object 클래스 중 equals() toString() hashCode()을 왜 오버라이딩 해야하는지 궁금증이 생겨 정리해보았다.

.equals()

equals() 메서드는 '객체간의 동등성 비교를 boolean 타입으로 반환' 하는 기능을 한다.

즉, 객체간의 '주소 값'을 비교한다.

public class Food {
	public String food;
	public int spicy;
	
	public Food() {}

	public Food(String food, int spicy) {
		this.food = food;
		this.spicy = spicy;
	}
}
public class Eat {
	public static void main(String[] arg) {
		Food food = new Food("떡볶이", 3);
		Food food2 = new Food("떡볶이", 5);
		Food food3 = new Food("떡볶이", 3);
		
		System.out.println(food == food2);
		System.out.println(food == food3);
		System.out.println(food2 == food3);
		
		System.out.println(food.equals(food2));
		System.out.println(food.equals(food3));
		System.out.println(food2.equals(food3));
        // 전부 false
	}
}

위의 예제에 foodfood3처럼 사람이 보기엔 같은 데 주소 값이 다르기에 false가 출력된다.

😵‍💫 ==.equals()가 헷갈려...
😃 일단 .equals()가 두 종류 있다는 걸 알아야한다.

  • String타입.equals()
  • Object타입.equals()

먼저 == 연산자는 두 객체의 주소 값을 비교한다.
String타입.equals()실제 값을 비교한다.
Object타입.equals()두 객체의 주소 값을 비교한다.

String타입.equals()equals()가 오버라이딩 되어있기 때문이다.

.equals() 오버라이딩

위의 예제처럼 .equals()를 통해 내용을 비교하고 싶다면 오버라이딩을 사용하면 해결된다. (음식 이름과 매운 정도가 같으면 같다고 정의한다.)

public class Food {
	public String food;
	public int spicy;
	
	public Food() {}

	public Food(String food, int spicy) {
		this.food = food;
		this.spicy = spicy;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Food) {
			Food fd = (Food) obj;
			if(this.food == fd.food && this.spicy == fd.spicy) {
				return true;
			} else {
				return false;
			}
		}
		return false;
	}
}
public class Eat {
	public static void main(String[] arg) {
		Food food = new Food("떡볶이", 3);
		Food food2 = new Food("떡볶이", 5);
		Food food3 = new Food("떡볶이", 3);

		System.out.println(food.equals(food2));		// false
		System.out.println(food.equals(food3));		// true
		System.out.println(food2.equals(food3));	// false
	}
}

.toString()

toString() 메서드는 '객체가 가지고 있는 값을 문자열로 반환' 하는 기능을 한다.

즉, 참조형 변수를 toString 하면 참조형 변수의 주소 값을 반환한다.
(정확히는 클래스명@주소 값 처럼 반환한다.)

public class Food {
	public String food;
	
	public Food() {}
	
	public Food(String food) {
		this.food = food;
	}
}
public class Eat {
	public static void main(String[] arg) {
    
		Food favorite = new Food("떡볶이");
		
		System.out.println(favorite);				// Food@24d46ca6
		System.out.println(favorite.toString());	// Food@24d46ca6
	}
}

😕 왜 favoritefavorite.toString()과 같은 값을 출력한걸까??

😀 System.out.print()을 사용할 때 참조형 변수를 넣으면
자동으로 toString()메서드가 작동한다.

✌️ 참고로 StringFile 클래스는 이미 재정의 되어있다.

  • String : 값을 반환
  • File : 주소 값을 반환
public class Test {
	public static void main(String[] arg) {
    	String food = "매운 떡볶이";
		File foodFile = new File("C\\떡볶이 레시피.txt");
		
		System.out.println(food);		// 떡볶이
		System.out.println(foodFile);	// C\떡볶이레시피.txt
	}
}

.toString() 오버라이딩

내가 만든 Food 클래스 또한 Object 클래스를 상속받고 있기에
오버라이딩을 사용해 Food만의 toString을 재정의 할 수 있다.

public class Food {
	public String food;
	
	public Food() {}
	
	public Food(String food) {
		this.food = food;
	}
    
    @Override
    public String toString() {
    	return "나는 " + this.food + "를(을) 정말 좋아한다.";
    }
}
public class Eat {
	public static void main(String[] arg) {
    
		Food favorite = new Food("떡볶이");
		
		System.out.println(favorite);				// 나는 떡볶이를(을) 정말 좋아한다.
		System.out.println(favorite.toString());	// 나는 떡볶이를(을) 정말 좋아한다.
	}
}

.hashCode()

hashCode()가 제일 이해가 안갔다...

hashCode() 메서드는 '객체를 지칭하는 고유한 값을 정수 값으로 반환' 하는 기능을 한다.

즉, 객체의 주소 값이다.

hashCode() 메서드를 이해하기 힘들었던 부분은 equals()를 오버라이딩하면 hashCode() 또한 재정의를 꼭 해야한다는 부분이 어려웠다.

예시를 봐보자

public class Food {
	public String food;
	public int spicy;
	
	public Food() {}

	public Food(String food, int spicy) {
		this.food = food;
		this.spicy = spicy;
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Food) {
			Food fd = (Food) obj;
			if(this.food == fd.food && this.spicy == fd.spicy) {
				return true;
			} else {
				return false;
			}
		}
		return false;
	}
}
public class Eat {
	public static void main(String[] arg) {
		Food food = new Food("떡볶이", 3);
		Food food2 = new Food("떡볶이", 5);
		Food food3 = new Food("떡볶이", 3);

		System.out.println(food.equals(food2));		// false
		System.out.println(food.equals(food3));		// true
		System.out.println(food2.equals(food3));	// false
        
        System.out.println(food.hashCode());		// 6179012
		System.out.println(food2.hashCode());		// 1159190
		System.out.println(food3.hashCode());		// 9258584
	}
}

foodfood3를 비교하면 true가 나온다.
하지만 .hashCode()를 사용하면 서로 다른 정수 값을 가진다.

🙄 결국 true를 출력했으니 된게 아닐까?
🤐 아니었다.
equals()hashCode()를 같이 재정의 해야되는 이유는
자바의 라이브러리, 컬렉션 프레임워크가 equals()hashCode() 둘 다 사용하기 때문이다.

.hashCode() 오버라이딩

위와 같은 문제는 .equals()만 재정의할 경우다.

아래와 같이 hashCode() 또한 재정의해주면 해결된다.

public class Food {
	public String food;
	public int spicy;
	
	public Food() {}

	public Food(String food, int spicy, int num) {
		this.food = food;
		this.spicy = spicy;
	}
    
    @Override
	public int hashCode() {
		return Objects.hash(food, spicy);
	}

	@Override
	public boolean equals(Object obj) {
		if(obj instanceof Food) {
			Food fd = (Food) obj;
			if(this.num == fd.num) {
				return true;
			} else {
				return false;
			}
		}
		return false;
	}
}
public class Eat {
	public static void main(String[] arg) {
		Food food = new Food("떡볶이", 3, 1);
		Food food2 = new Food("떡볶이", 5, 2);
		Food food3 = new Food("떡볶이", 3, 1);

		System.out.println(food.equals(food2));		// false
		System.out.println(food.equals(food3));		// true
		System.out.println(food2.equals(food3));	// false
        
        System.out.println(food.hashCode());		// 1433263365
		System.out.println(food2.hashCode());		// 1433263367
		System.out.println(food3.hashCode());		// 1433263365
	}
}

끝!

0개의 댓글