티스토리 뷰

728x90
반응형

@Override 애너테이션을 일관되게 사용하라


  • @Override는 메서드 선언에만 달 수 있으며, 이 애너테이션이 선언되었다는 것은 상위 타입의 메서드를 재정의했음을 의미합니다.

 

🧨 잘못된 코드

  • Set은 중복을 허용하지 않으니 10개가 출력될거 같지만 실상은 그렇지 않습니다.(110개 출력)
  • 이러한 문제가 발생하는 이유는 Food 클래스의 equals는 Object 클래스의 equals 메서드를 재정의한게 아닌 오버로딩일 하였기 때문입니다.
  • Object 클래스의 equals는 매개변수로 Object 타입을 받습니다. 하지만 Food 클래스의 equals 메서드는 Food 타입을 받고 있습니다. 이는 재정의가 아닌 다중정의가 된것이고 Set에서는 Object의 equals를 사용하여 객체 식별성을 비교하기 때문에 모두 다른 객체로 인식하는 것입니다.
public class Food {

    private final int id;
    private final String name;

    public Food(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public boolean equals(Food food) {
        return food.id == this.id && food.name == this.name;
    }

    public int hashCode() {
        return 31 * id;
    }
}

public class Example {
    public static void main(String[] args) {
        Set<Food> foods = new HashSet<>();
        for (int i = 0; i < 10; i++) {
            foods.add(new Food(i, "피자 : " + i));
            for (int j = 0; j < 10; j++) {
                foods.add(new Food(j, "피자 : " + j));
            }
        }

        System.out.println(foods.size()); // 110
    }
}

 

💡 @Override 애너테이션 활용

  • equals 메서드 선언에 @Override 애너테이션을 선언했지만 컴파일 오류가 발생한것을 알 수 있습니다.
  • error: method does not override or implement a method from a supertype @Override

 

💡 @Override 애너테이션 수정

  • equals 메서드를 제대로 재정의한 뒤 다시 실행을 해보면 정상적으로 10이 출력되는것을 확인할 수 있습니다.
public class Food {

    private final int id;
    private final String name;

    public Food(int id, String name) {
        this.id = id;
        this.name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Food food = (Food) o;
        return id == food.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

public class Example {
    public static void main(String[] args) {
    
        Set<Food> foods = new HashSet<>();
        for (int i = 0; i < 10; i++) {
            foods.add(new Food(i, "피자 : " + i));
            for (int j = 0; j < 10; j++) {
                foods.add(new Food(j, "피자 : " + j));
            }
        }

        System.out.println(foods.size()); // 10
    }
}

 

💡 @Override 애너테이션 사용 방법

  • @Override 애너테이션을 사용하면 컴파일 오류를 통해 미리 사고를 방지할 수 있습니다.
  • 상위 클래스의 메서드를 재정의하려는 모든 메서드에 @Override 애너테이션을 선언해야합니다. 하지만 예외는 구체 클래스에서 상위 클래스의 추상 메서드를 재정의할 때는 굳이 @Override 애너테이션을 선언하지 않아도 됩니다. 이유는 구체 클래스인데 아직 구현하지 않은 추상 메서드가 있다면 컴파일러가 친절히 알려줍니다.

 

✔️ 정리

  • 재정의한 모든 메서드에 @Override 애너테이션을 의식적으로 선언하면 실수했을 때 컴파일러가 친절히 알려줍니다.
  • 예외는 한가지 뿐입니다. 구체 클래스에서 상위 클래스(인터페이스 및 추상 클래스)의 추상 메서드를 재정의한 경우엔 애너테이션을 선언하지 않아도 무방합니다.

 

 

 

728x90
반응형