Skip to content

Latest commit

 

History

History
127 lines (104 loc) · 4.28 KB

40. 재정의 할 때는 항상 @Override 애너테이션을 붙여라.md

File metadata and controls

127 lines (104 loc) · 4.28 KB

재정의 할 때는 항상 @Override 애너테이션을 붙여라

매서드를 재정의 할 때, @Ovveride 애너테이션을 붙이지 않으면 다음과 같은 실수를 할 수 있다

public class TrumpCard {
    private final Symbol symbol;
    private final Number number;

    public TrumpCard(Symbol symbol, Number number) {
        this.symbol = symbol;
        this.number = number;
    }

    public boolean equals(TrumpCard card) {
        // 심볼과 숫자가 동일하면, 같은 객체라 한다  
        return card.symbol == symbol && card.number == number;
    }

    public int hashCode() {
        return 31 * symbol.hashCode() + number.hashCode();
    }

    public static void main(String[] args) {
        Set<TrumpCard> trumpCards = new HashSet<>();

        // 스페이드 카드를 A ~ K,J,Q 까지 두 번 set에 추가한다
        for (Number value : Number.values()) {
            trumpCards.add(new TrumpCard(Symbol.SPADE, value));
        }
        for (Number value : Number.values()) {
            trumpCards.add(new TrumpCard(Symbol.SPADE, value));
        }
        System.out.println(trumpCards.size());
    }
}

같은 스페이드 심볼 카드를 A ~ J,Q,K 까지 생성하기에, 원하는 출력 결과는 13이다
하지만 실제로 실행하면 콘솔에는 26이 나온다
이유는 Objectequals를 재정의 한 것이 아닌 다중정의 해버렸기 때문이다
재정의를 위해 @Override 애너테이션을 붙인다면 빨간 줄과 함께 오류가 뜰 것이다

@Override // 실제로는 애너테이션에 빨간 줄이 그인다!  
public boolean equals(TrumpCard card) {
    return card.symbol == symbol && card.number == number;
}

Method does not override method from its superclass

이는 재정의한다고 명시했는데, 정작 쓴 코드가 Object의 equals와 시그니처가 달라 다중정의 되었기 때문이다
매개변수를 Object로 수정하거나, 아니면 처음부터 인텔리제이가 만들어주는 코드를 기반으로 작성하도록 하자

@Override
public boolean equals(Object o) {
    if (!(o instanceof TrumpCard))
        return false;
    TrumpCard card = (TrumpCard) o;
    return card.symbol == symbol && card.number == number;
}

단, 구체 클래스에서 상위 클래스의 추상 메서드를 구현할 때는 달지 않아도 된다
제대로 구현하지 않은 클래스가 있으면, 컴파일 시점에서 알 수 있기 때문이다

// 오류로 컴파일되지 않는다 
public abstract class Crew {
    public abstract boolean isLevel1();
    public abstract String helloWorld();
}

public class BackendCrew extends Crew{
    public boolean isLevel1(String mission) {
        if (mission.equals("blackjack"))
            return true;
        return false;
    }
    public String helloWorld() {
        return "System.out.println(\"Hello World!\");\n";
    }
}

인터페이스에 디폴트 매서드가 없다면, 깔끔한 코드 유지를 위해 @Override를 쓰지 않아도 좋다
하지만 디폴트 메서드가 존재한다면, @Override로 시그니처가 올바른지 재차 확인할 수 있다

public interface Crew {
    default boolean isLevel1() {
        return true;
    }
    String helloWorld();
}

// 의도가 재정인데 @Override가 없다면, TrumpCard 코드처럼 다중정의가 일어난다  
public class BackendCrew implements Crew {
    // 컴파일되지 않는다 
    @Override
    public boolean isLevel1(String mission) {
        if (mission.equals("blackjack"))
            return true;
        return false;
    }
    @Override
    public String helloWorld() {
        return "System.out.println(\"Hello World!\");\n";
    }
}

결론

재정의하는 모든 메서드에 @Override를 달면, 컴파일 시점에 실수를 고칠 수 있다
추상 메서드 구현이나, 디폴트 메서드가 없는 인터페이스 구현 때는 달지 않아도 된다
하지만 손해볼 것 없으니 인텔리제이가 시키는 대로 하자

참고글