Skip to content

Item 40. @Override 애너테이션을 일관되게 사용하라 #37

@lain1nya

Description

@lain1nya

Chapter : 6. 열거 타입과 애너테이션

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

Assignee : Lainlnya


🍑 서론

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

🍑 본론

@override를 일관되게 사용하면 여러 가지 버그들을 예방할 수 있다.

public class Bigram {
	private final char first;
	private final char second;
	
	public Bigram(char first, char second) {
		this.first = first;
		this.second = second;
	}
	
	public boolean equals(Bigram b) {
		return b.first == first && b.second == second;
	}
	
	public int hashCode() {
		return 31 * first + second;
	}
	
	public static void main(String[] args){
		Set<Bigram> s = new HashSet<>();
		for (int i = 0; i < 10; i++) {
			for (char ch = 'a'; ch <= 'z'; ch++) 
				s.add(new Bigram(ch, ch));
		}
		System.out.println(s.size()); // 260
	}
}

왜 size가 260이 출력될까 ?

원래 set은 중복을 허용하지 않으므로 26이 출력되어야 한다.

equals 메서드를 재정의하려 한 것으로 보이고, hashCode 또한 함께 재정의했다. 하지만 여기서는 equals를 ‘재정의(overriding)’한 게 아니라 ‘다중정의(overloading)’했다.

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    return (anObject instanceof String aString)
            && (!COMPACT_STRINGS || this.coder == aString.coder)
            && StringLatin1.equals(value, aString.value);
}

👆 자바 공식 문서에 나와있는 equals

즉, 매개변수의 타입이 Object가 아니기 때문에, overriding이 아닌 overloading이 되어, equlas를 새로 정의한 형태가 되었다. 따라서 == 만 확인했기 때문에 서로 다른 객체로 인식하여, 260을 출력하게 되었다.

여기서 컴파일러가 오류를 찾아내게 하려면, 아래처럼 재정의한다는 의도를 명시해야 한다.

@Override
public boolean equals(Bigram b) {
	return b.first == first && b.second == second;
}

// Bigram. java: 10: method does not override or implement a method 
// from a supertype
// 이라는 오류 발생
@Override
public boolean equals(Object o) {
	if (!(o instanceof Bigram))
		return false;
	Bigram b = (Bigram) o;
	return b.first == first && b.second == second;
}

⭐️ 상위 클래스의 메서드를 재정의하려는 모든 메서드에 @Override 애너테이션을 달자

예외: 구체 클래스에서 상위 클래스의 추상 클래스를 재정의할 때는 달지 않아도 된다.

✅ 구체 클래스(concrete class)란?
모든 연산에 대한 구현을 가지고 있는 클래스를 의미하며, 추상 클래스가 아닌 클래스를 모두 concrete class라고 한다.
new 키워드로 객체를 생성할 수 있는 클래스이며 클래스의 모든 메서드를 완벽하게 구현한 클래스를 의미한다.

구체 클래스인데 아직 구현하지 않은 추상 메서드가 남아 있다면 컴파일러가 그 사실을 알려준다.

올바른 사용법

  1. IDE에서 관련 설정을 활성화해놓으면 @Override가 달려있지 않은 메서드가 실제로는 재정의를 했다면 경고를 준다.
  2. @Override 는 클래스뿐 아니라 인터페이스의 메서드를 재정의할 때도 사용할 수 있다. (자바에서 인터페이스에서 디폴트 메서드를 지원하기 시작했기 때문에, 디폴트 메서드가 없음을 안다면 override를 생략해 적는 것이 좋다.)
  3. 추상 클래스나 인터페이스에서는 상위 클래스나 상위 인터페이스의 메서드를 재정의하는 모든 메서드에 @Override 를 다는 것이 좋다. 예를 들어 Set 인터페이스의 경우 Collection 인터페이스를 확장했지만 새로 추가한 메서드는 없기에 모두 @Override 를 달아 실수로 추가한 메서드가 없음을 보장했다.

🍑 결론

재정의한 모든 메서드에 @Override 애너테이션을 의식적으로 달면 실수했을 때 컴파일러가 바로 알려준다.

구체 클래스에서 상위 클래스의 추상 메서드를 재정의한 경우엔 해당 애너테이션을 달지 않아도 된다.


Referenced by

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions