Java - 메소드 시그니처(Method Signature)

메소드 시그니처(Method signature)는 자바에서 메소드를 정의할 때 메소드를 구별하는 ID와 같습니다.

메소드의 이름이 같더라도 인자가 다르면 메소드 정의가 가능하며(Method Overloading), 이것은 Method signature가 다르기 때문입니다. 만약 Method signature가 같으면, 이미 정의된 메소드라는 에러와 함께 컴파일이 실패합니다.

이 글에서는 Method signature가 무엇인지 예제와 함께 설명합니다.

Method signature

아래 클래스는 func라는 2개의 메소드가 정의하였습니다. 두 메소드의 signature는 다르기 때문에 컴파일이 가능합니다.

public class MethodSignature {

  private void func() {
      System.out.println("Signature is: func()");
  }

  public void func(int arg1) {
      System.out.println("Signature is: func(int arg1)");
  }
}

signature는 메소드 이름과 인자로 구성됩니다. 즉, 리턴 값은 signature에 영향을 주지 않습니다.

  • private void func()의 signature: func()
  • private void func(int arg1)의 signature: func(int arg1)

아래와 같이 메소드를 정의하면 컴파일이 실패합니다. return 타입과 throws는 Method signature에 영향을 주지 않는다는 것을 볼 수 있습니다.

public int func2() {
    System.out.println("Signature is: func2()");
    return 1;
}

public void func2() throws IllegalStateException {
    System.out.println("Signature is: func2()");
    throw new IllegalStateException();
}

컴파일 에러 로그:

Error:(23, 17) java: method func2() is already defined in class example.MethodSignature

Generics의 Method signature

다음과 같은 Generic 클래스가 있습니다. 여기서 T는 컴파일될 때 타입이 결정되며, func(T arg1)의 signature도 컴파일 때 결정됩니다.

public class MethodSignature2<T> {

    public void func(T arg1) {
        System.out.println("Signature is: func(T arg1)");
    }

    public void func(Integer arg1) {
        System.out.println("Signature is: func(Integer arg1)");
    }
}

다음과 같이 TDouble로 객체를 생성하면

MethodSignature2<Double> obj = new MethodSignature2<>();
obj.func(10);
obj.func(10.10);

다음과 같은 메소드로 형태로 컴파일되며, 중복되는 signature가 없기 때문에 컴파일은 성공합니다.

public void func(Double arg1) {
    System.out.println("Signature is: func(T arg1)");
}

public void func(Integer arg1) {
    System.out.println("Signature is: func(Integer arg1)");
}

코드를 실행해보면 다음과 같이 출력됩니다. 예상한 것처럼 인자의 타입에 따라 다른 메소드가 호출되었습니다.

Signature is: func(Integer arg1)
Signature is: func(T arg1)

하지만 다음과 같이 T를 Integer로 객체를 생성하고 func()를 호출할 때,

MethodSignature2<Integer> aa = new MethodSignature2<>();
aa.func(10);

다음과 같은 컴파일 에러가 발생합니다.

Error:(10, 11) java: reference to func is ambiguous
  both method func(T) in example.MethodSignature2 and method func(java.lang.Integer) in example.MethodSignature2 match

위의 객체는 아래와 같은 메소드 형태로 컴파일 되며, 동일한 Signature를 갖고 있는 메소드가 중복으로 정의됩니다.

public void func(Integer arg1) {
    System.out.println("Signature is: func(T arg1)");
}

public void func(Integer arg1) {
    System.out.println("Signature is: func(Integer arg1)");
}

Bounded Generics의 Method signature

<T extends Number>는 T가 Number를 상속하는 클래스로만 제한을 둔다는 의미입니다. 이렇게 제한을 두는 것을 Bounded Generics라 합니다.

아래와 같이 Bounded Generics로 정의한 클래스가 있습니다.

public class MethodSignature3<T extends Number> {

    public void func(T arg1) {
        System.out.println("Signature is: func(Number arg1)");
    }

    public void func(Number arg1) {
        System.out.println("Signature is: func(Number arg1)");
    }
}

위 코드는 컴파일 실패합니다. 그 이유는 T는 Number로 변환되어 컴파일되기 때문입니다.

public void func(Number arg1) {
    System.out.println("Signature is: func(Number arg1)");
}

public void func(Number arg1) {
    System.out.println("Signature is: func(Number arg1)");
}

컴파일 에러 로그:

Error:(10, 17) java: name clash: func(java.lang.Number) and func(T) have the same erasure

정리

Method signature에 대해서 알아보았고, 메소드 오버로딩을 하는 방법을 알아보았습니다. Generics와 Bounded Generics이 컴파일 될 때 T의 타입이 변경되기 때문에 예상하지 못한 컴파일 에러가 발생하는 경우를 살펴보았습니다.

Loading script...

Related Posts

codechachaCopyright ©2019 codechacha