[Java] 메서드 시그니처 vs 메서드 타입
더블 디스패치에 대해 공부하려고 토비님의 유튜브 영상을 보다가 메서드 시그니처(method signature)와 메서드 타입(method type)에 대해 정리해주시는 것을 보고 정리해둘 필요가 있을 것 같아 포스팅해봅니다.
메서드 시그니처(Method Signature)
시그니처, 말 그대로 서로다른 메서드를 구분하는 근거가 되는 요소입니다. 메서드 오버라이딩을 할 때 중요합니다.
메서드 시그니처의 구성 요소
- 메서드 이름
- 파라미터 리스트
이 두 가지가 같으면 메서드를 오버라이딩할 수 있으며, 이 두 가지가 같은 메서드가 한 클래스 내에 두 개 이상 정의되어 있으면 메서드 중복으로 컴파일 에러가 발생합니다.
여기서 파라미터 리스트라는 것은 파라미터의 타입, 개수, 순서를 말합니다. 예를 들어 파라미터의 타입과 개수가 같더라도 순서가 다르면 다른 메서드로 인식됩니다.
public class Demo {
public String methodA(int intA, String stringA) {
return "int string";
}
public String methodA(String stringA, int intA) {
return "string int";
}
public static void main(String[] args) {
Demo demo = new Demo();
demo.methodA(1, "");
demo.methodA("", 1);
}
}
❗️주의! 메서드의 리턴 타입은 메서드 시그니처가 아니다. 즉 메서드 이름과 파라미터 타입이 같고 리턴 타입만 다르면 컴파일 에러가 발생한다.
추가적으로 상속을 할 때는 반환타입이 같아야하는데, 오버라이딩 하는 쪽의 리턴 타입이 Covariant하면 타입이 달라도 됩니다.
public class Parent {
Parent hello(int a) {
return null;
}
}
class Child extends Parent {
@Override
Child hello(int a) {
return null;
}
}
메서드 타입(Method Type)
메서드 타입은 Java8의 메서드 레퍼런스를 사용할 때 중요한 개념. 메서드 타입이 같으면 메서드 레퍼런스를 사용할 수 있다.
메서드 타입 구성 요소
- 리턴 타입
- 타입 파라미터
- 아규먼트 타입
- 예외
근데 토비님 말씀을 듣고 실험을 해봤는데 리턴 타입이 달라도 메서드 레퍼런스가 잘 동작해서 의문이 든다;;
예를 들어, List의 forEach 메서드는 매개변수로 Consumer를 받는데, Consumer는 인자가 하나고 반환타입이 void인 함수형 인터페이스이다. 그런데 아래와 같이 리턴 타입이 있는 메서드를 전달해도 잘 동작하는 것을 볼 수 있다.
import java.util.Arrays;
import java.util.List;
public class Demo {
public static void main(String[] args) {
List<Integer> arr = Arrays.asList(1, 2, 3, 4, 5);
arr.forEach(Foo::print);
}
}
class Foo {
public static int print(int a) {
System.out.println(a);
return a;
}
}
그래서 Method Type이라는게 정확히 뭔지 알아보려고 자료를 찾아봐도 잘 나오지 않아서 정확히 확인을 못하겠다.
내가 예시를 잘못 사용한건지, 설명을 제대로 이해 못한건지,, 아시는 분 있으면 댓글 달아주시면 감사하겠습니다.