최근에 갑자기 동적 바인딩과 정적 바인딩에 관한 내용이 떠올랐는데, 말로 설명하지 못하는 모습을 보고 정확히 알지 못한다는 것을 알게 되었다. 그래서 정리하려고 한다.

동적 바인딩 vs 정적 바인딩

  • 동적 바인딩(Dynamic Binding)
    • 다형성을 사용하여 메소드를 호출할 때, 발생하는 현상이다.
    • 실행 시간(Runtime) 즉, 파일을 실행하는 시점에 성격이 결정된다.
    • 실제 참조하는 객체는 서브 클래스이니 서브 클래스의 메소드를 호출한다.
  • 정적 바인딩(Static Binding)
    • 컴파일(Compile) 시간에 성격이 결정된다.
    • 변수의 타입이 수퍼 클래스이니 수퍼 클래스의 메소드를 호출한다.

[Sample Code]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* created by victory_woo on 2020/07/06
*/
public class PolymorphismTest {
public static void main(String[] args) {
SuperClass superClass = new SuperClass();
superClass.methodA();
superClass.methodB();


SuperClass subClass = new SubClass();
subClass.methodA();
subClass.methodB();
}
}


class SuperClass {
void methodA() {
System.out.println("SuperClass A ");
}

static void methodB() {
System.out.println("SuperClass B");
}
}

class SubClass extends SuperClass {
@Override
void methodA() {
System.out.println("SubClass A");
}

static void methodB() {
System.out.println("SubClass B");
}
}

// 예상 결과
SuperClass A
SuperClass B
SubClass A
SubClass B

// 실제 결과
SuperClass A
SuperClass B
SubClass A
SuperClass B
  • SubClass는 SuperClass의 methodA()를 상속받아 오버라이딩했다.
  • methodA()가 어떤 클래스의 메소드인지 Runtime 즉, 클래스 파일이 실행되는 시점에 결정된다.
  • 다시 말해, 동적 바인딩은 Runtime 시점에 해당 메소드를 구현하고 있는 실제 객체 타입을 기준으로 찾아가서 실행될 함수를 호출한다.
  • subClass 참조 변수로 접근 가능한 것은 부모 클래스의 멤버이지만, 자식 클래스에서 메소드를 오버라이딩했으므로 자식 클래스의 메소드를 호출한다.
  • subClass 참조 변수는 런타임시에 SubClass의 methodA() 호출
  • subClass 참조 변수는 컴파일시에 SuperClass의 static 메소드인 methodB() 호출
  • 결론
    • 모든 인스턴스 메소드는 Runtime에 결정된다.
    • 클래스(static) 메소드와 인스턴스 변수는 Compile 시에 결정된다.
    • 따라서 instance인지, statice인지에 따라서 달라진다.

Static Method Overriding

동적 바인딩과 정적 바인딩의 개념과 차이를 알았으므로 static 메소드의 오버라이딩 여부에 대해서 이야기 해 볼 수 있을 것 같다. 예전에 "static 메소드는 오버라이딩 된다"라고 말했지만, 이유를 말할 수 없었던 기억이 난다. 이제는 말할 수 있을 것 같다.

결론 : static 메소드는 오버라이딩 할 수 없다.

  • static 메소드는 컴파일 시, 메모리에 올라가고 메소드 영역에 존재한다.
  • 즉, 객체 생성과 관련이 없고 해당 클래스로부터의 모든 인스턴스가 공유한다.
  • 따라서 static 메소드가 오버라이딩 된다면 논리적으로 맞지 않는다.

위의 Sample Code를 통해서 static 메소드가 오버라이딩 되지 않는다는 것을 알았다. 이유는 static 메소드는 클래스가 Compile 되는 시점에 결정되지만, Override의 경우에는 Runtime 시점에 사용될 메소드가 결정되기 때문이다. 그래서 애초에 성립하기 어렵다.

static 메소드의 경우, 클래스 단위로 만들어지기 때문에 객체 단위로 형성되는 Override는 성립될 수 없다는 게 결론이다.

  • instance method
    • Runtime 시 해당 메소드를 구현하고 있는 실제 객체를 찾아 호출한다.
    • 즉, 다형성을 보여준다.
  • static method
    • JVM과 컴파일러 모두 static method에 대해서는 실제 객체를 찾는 작업을 시행하지 않기 때문에 static method(class method)의 경우에는 Compile 시점에 선언된 타입의 메소드를 호출한다.
    • 따라서 static method에서는 다형성이 적용되지 않는다.
  • static 메소드는 원칙적으로 오버라이딩이 안되지만, 아래처럼 가능하게끔 할 수 있다.
  • 이를 하이딩(hiding)이라고 한다. 이론적으로만 존재할 뿐, 실제 프로그래밍에서 클래스를 설계할 때, 추천되는 방법은 아니다.
    1. 오버라이드된 static method를 정확하게 호출하려면 메소드가 포함된 실제 객체로 선언해야 한다.
    2. 하이딩의 사용은 피하는게 좋다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// 기본적인 상속과 구현.
public class A{
public static void test() {
System.out.println("A test()");
}
}

class B extends A{
@Override // 컴파일 오류
public static void test() {
System.out.println("B test()");
}
}
// 하이딩.
public class A{
public static void test() {
System.out.println("A test()");
}
}

class B extends A{
public static void test() {
System.out.println("A test()");
}
}

Reference