들어가며
오버로딩은 신중하게 작성해야 한다. 다음 코드를 보자.
1 | public class main { |
다음 코드는 오버라이딩된 클래스의 메소드를 호출하는 경우에는 기대하는 동작을 수행하고 오버로딩된 메소드의 호출시엔 기대하는 동작을 수행하지 않는다. 이유는 오버라이딩된 메소드는 동적으로 런타임에 결정되고 오버로딩된 메소드는 정적으로 컴파일 타임에 결정되기 때문이다. 즉 오버로딩된 메소드 사이에는 객체의 런타임 타입은 중요하지 않고 선택은 컴파일 타임에, 오직 매개변수의 컴파일 타임 타입에의해 이뤄진다.그러니 오버로딩이 혼동을 일으키는 상황을 피해야한다. 안전하고 보수적으로 가려면 매개변수 수가 같은 오버로딩 메소드는 만들지 말자. 오버로딩하는 대신 메소드 이름을 재정의하는 방법도 있긴하다. 예를들어 ObjectOutputStream
클래스의 write메소드는 writeInt(int)
writeLong(long)
과 같이이름을 재정의하는 방식을 택했다.
생성자는 이름을 다르게 지을 수 없으니 두번째 생성자부터는 오버로딩이 된다. 하지만 이 때는 정적 팩터리라는 방법이 존재하며 생성자는 오버라이딩이 될 수 없으니 오버로딩과 오버라이딩이 혼용될 여지는 없다.
매개변수 수가 같은 오버로딩된 메소드가 많더라도 매개변수중 하나 이상이 근본적으로 다르다면 헷갈릴 이유가 없다. 근본적으로 다르다는 것은 null이 아닌 두 타입의 값을 서로 어느쪽으로든 형 변환이 불가능하단 의미이다. 또한 메소드를 오버로딩할 때 서로 다른 함수형 인터페이스라도 같은 위치의 인수로 받으면 위와 같은 오류가 난다. 함수형 인터페이스는 근본적으로 같으며 overloading resolution은 기대한 대로 동작하지 못한다.
암시적 타입 람다식이나 부정확한 메소드 참조 같은 인수 표현식은 목표 타입이 선택되기 전에는 그 의미가 정해지지 않기 때문에 적용성 테스트때 무시된다.