@Override 와 가상함수 테이블

서재환·2021년 12월 16일
0

JAVA

목록 보기
15/16

업캐스팅한 자료형으로 @Override 한 함수를 사용할 경우 Override 한 함수를 사용할 수 있는 이유?

업캐스팅

A -> B 

위와 같이 클래스 A가 클래스 B를 상속한다고 했을 때

B instance = new A();

같이 작성했을 때 참조변수 instance가 접근할 수 있는 것은 B 클래스가 갖고 있는 변수와 메서드이다. 
이 떄 @Override한 함수를 사용하게 될 때 내 머리 속에 의문이 있었는데 그것은 어떻게 @Override한
함수를 instance가 사용할 수 있냐는 것이었다.

내 입장에서 @Override한 함수는 instance 영역에 있는 거라서 B 자료형으로 업캐스팅 한 경우 사용할
수 없다고 생각했기 때문이다.

오늘은 위와 같은 질문에 답을 해보고자 글을 작성하게 되었다. 지금도 완벽하게 이해하고 있는 것은 아니
지만 업캐스팅 할 경우(상속 class의 자료형으로의 변환) 접근할 수 있다라는 부분을 확실히 하고 그와 
관련된 개념을 정리하는 시간으로 갖도록 하겠다.

설명을 할 때에는 예시만한게 없지. 아래 코드를 보자

public class TestMethod {

	int num;
	
    	TestMethod() {};
    
	void aaa() {
		System.out.println("aaa() 호출");
	}
	
	public static void main(String[] args) {
		
		TestMethod a1 = new TestMethod();
		a1.aaa();
		
		TestMethod a2 = new TestMethod();
		a2.aaa();
	}
    
    	public void print() {
	    	System.out.println("TestMethod 의 함수호출");  
    	}

}

프로그램이 로드 되면서 위의 코드는 아래의 영역에 각각 올라가게 된다. 하나씩 살펴보자
TestMethod 클래스 입장에서 main은 함수이다. 함수 내부의 지역 변수는 스택 메모리에 
올라간다. 클래스의 변수는 힙메모리에 올라가게 되고 메서드는 Code영역에 올라각 된다.

정리
클래스 내 메서드 내 지역변수 -> Stack
클래스 내 변수 -> Heap
클래스 내 메서드 -> Code
클래스 내 static -> Data

위의 클래스를 TestMethod2가 상속 받는다고 하자. 

public class TestMethod2 extends TestMethod {
    @Override
    public void print() {
    	System.out.println("TestMethod2의 함수호출");
    }
}

그랬을 때 아래의 결과는 TestMethod의 함수를호출할까? 아니면 TestMethod2의 메서드를 호출할까?

public class Test {
    public static void main(String[] args) {
        TestMethod testMethod2 = new TestMethod2();
        testMethod2.print(); // ???
    }
}

결과는 TestMethod2의 함수를 호출한다. 함수의 호출은 가상 메서드 테이블과 관련이 있는데 가상 메
서드 테이블에 대해서 알아보기로 하자.

Virtual Method Table

new 생성자로 객체를 생성하게 되면 객체는 Heap 메모리에 생성되게 된다. 위의 경우 testMethod2
라는 객체가 heap 메모리에 올라가게 된다. new TestMethod2()로 생성하였기 때문에 Heap 메모리
에는 상속받은 class 내부의 변수와 메서드 그리고 본인의 메서드가 Heap에 올라가 있다.

가상 메서드 테이블이란 Heap 영역에 객체가 생성되는 것처럼 하나의 객체에 하나의 가상 메서드 테
이블을 갖는다. 가상 메서드 테이블에는 메서드의 주소가 적혀있다. 

가상 메서드 테이블이 힙에 올라가는 객체처럼 객체 별로 각각 만들어지는 반면 Code(메서드) 영역
에 있는 함수는 중복돼서 올라가지 않는다.

따라서 TestMethod2에서 TestMethod 함수를 호출 할 경우 가상 함수 테이블 내의 메서드는 에 있
는 주소값을 참조하여 해당 함수를 실행하게 된다.

그래서 TestMethod testMethod2 = new TestMethod2() 에서 @Override한 print 함수에 어떻게 접근하냐구요?

그래서 heap 메모리에 new TestMethod2() 객체가 생성이 일단 되고 Code 영역에 메서드가 등록이 될 것이다.
@Override한 print() 함수가 등록이 될것이다. TestMethod의 print()와는 다른 주소를 갖고 있을 것이기 때
문이다.

그리고 업캐스팅을 할 경우(TestMethod testMethod2 = new TestMethod2()) @Override한 메서드 print()
함수에 접근할 수 있게 허용했을 것이 나의 피셜이다. TestMethod2가 가지고 있는 지역 변수 또는 자체 함수에
는 접근할 수 없지만 @Override한 함수에 접근 가능 한 것을 보면 해당 메서드로 바인딩을 시켜놓은 것이 논리
이기 때문이다.

정리하면 상속상태에 있는 자식 클래스가 조상 형으로 업캐스팅해 생성자 함수를 통해 인스턴스를 생성했을 때 
@Override한 함수의 경우 가상 함수 테이블에서 메서드의 새로운 주소를 가지며 @Override한 함수를 호출 
했을 경우 Code영역에 있는 메서드 주소에 접근 가능해서 실행가능해지는 것이 결론이다.

논리적인 내피셜이라 다소 설명이 빈약할 수 있다고 생각하고 틀린 부분이 있다면 댓글 달아주시면 수정하도록 하겠
습니다. 그럼 20000

0개의 댓글