2017년 7월 6일 목요일

[Java] 메소드 호출(Method Call)과 다이나믹 바인딩(Dynamic Binding)

우리가 메소드를 호출할 때 어떤 일이 일어날까, 왜 수퍼클래스의 메소드를 호출했는데 상속받은 객체의 메소드가 호출되는지를 알려면 자바(Java)에서의 메소드 호출법을 이해해야한다. 예를들어 우리가 클래스 c의 인스턴스인 x 객체의 f(y)라는 함수를 호출한다 가정할 때, x.f(y)이런식으로 호출할것이다. 이때 우리눈에 보이지 않는 컴퓨터세상에서는 어떤일이 일어나는지를 알아보자.
  1. 컴파일러가 선언된 객체의 형(type)과 메소드 이름을 찾아본다. 아마 파라미터만 다르고 f 라는 이름을 가진 메소드들이 많을것이다. 컴파일러는 클래스 c와 c의 수퍼클래스의 모든 메소드f 를 종합한다. 이제 컴파일러가 호출 대상 메소드들을 모두 종합했다.
  2. 컴파일러가 메소드 호출시 제공된 아규먼트(argument)들의 형(type)을 분석한다. 제공된 아규먼트들과 일치하는 파라미터를 가진 메소드 f가 있다면 해당 메소드를 호출한다. 이 과정을 overloading resolution이라고 한다. 참고로 overloading이란 이름은 같으나 파라미터가 틀린, 즉 method signature(메소드 이름+파라미터)가 틀린 메소드들을 선언하는것을 의미한다. 우리 가정상에서는 x가 String 타입일시 f(String x)라는 시그니쳐를 가진 메소드가 호출되고, x가 int 타입이라면 f(int x) 시그니쳐를 가진 메소드가 호출된다. 만약 double형에서 int형으로, 섭클래스 객체에서 수퍼클래스 객체로 타입변환이 필요하다면 이 과정은 조금 더 복잡해지게된다. 만약 컴파일러가 타입변환을 적용하고 서도 파라미터가 일치하는 메소드를 찾지 못했다면 에러가 발생한다. 그렇지 않다면, 컴파일러가 호출할 메소드의 이름과 파라미터 타입을 결정하게된다. 
  3. 만약 메소드가 private, static, final 속성을 가지거나, 생성자(Constructor) 메소드라면, 컴파일러가 바로 해당 메소드를 호출한다. 이 과정을 static binding이라고 한다.
  4. 만약 3번의 경우가 아니라면, 메소드는 implicit parameter, 즉 x 객체의 실제 타입에따라 결정된다.  이 과정을 dynamic binding이라고 한다.
  5. 프로그램이 실행되는동안 메소드 호출을 위해 dynamic binding이 진행될 때, 자바 가상머신은 implicit parameter, x가 참조하는 객체의 실제 타입에 맞는 메소드를 호출하게된다. x의 실제 타입이 클래스 X가 되고, 클래스 X는 클래스 W를 상속한다고 할때, 2번과정에서 찾은 메소드 f들 중에 클래스 X에 선언된 메소드 f가 있다면 그 메소드를 호출한다. 만약 아니라면, X가 상속하는 클래스, 즉 클래스 W에 선언된 메소드 f를 찾아본다. 그게 아니라면 하위 -> 상위 클래스로 선언된 메소드들을 찾아간다. 이 과정은 매우 많은 반복이 이뤄지는 과정이라, 가상머신이 미리 각 클래스의 메소드 시그니쳐들을 모아둔 데이터베이스를 작성하고, 실제로는 데이터베이스를 찾아보는 형식으로 진행된다. 
이게 간략하게 요약한 메소드호출의 과정이다. 물론 더 세세하게 파고든다면 엄청 긴 과정이되겠지만... 

다이나믹 바인딩(Dynamic Binding)은 매우 중요한 특징이다. 다이나믹 바인딩은 원래 있던 코드를 수정하지 않고도 프로그램을 확장할 수 있는 확장성을 준다. 언제든 상속(Inheritance)을 통해 설계를 확장할 수 있기 때문인데, 다이나믹 바인딩이 없다면 메소드 오버라이딩(method overriding)과 같은 상속만의 특성도 작동하기 때문이다.

댓글 없음:

댓글 쓰기