인터페이스와 추상클래스의 차이는 단일상속과 다중구현에 있다. 추상클래스에서 동일한 이름과 파라미터를 가진 메서드를 사용할 때 발생하는 다이아몬드 문제를 해결해 줄 수 있는게 인터페이스의 기능이다.
그래서 인터페이스는 왜 다중상속이 될까?
인터페이스는 구현체가 없기 때문에 다중 상속을 지원한다. 이말은 추상 클래스와 달리 인터페이스는 단순히 메서드 시그니처만 정의하며, 구체적인 구현은 포함하지 않는다. 그래서 다중 상속을 하더라도 충돌이 발생하지 않는다.
다중 상속 시 두 인터페이스가 같은 메서드를 정의하고 있어도 구현체는 클래스에서 결정되기 때문에 문제가 없다.
근데 이 "구현체가 아무것도 없으니까" 라고 말하면 뭔가 부족하다. 뭔가.. 간지럽다. 왜 그런 생각을 했냐면
interface A {
void sayHello(); // 일반 메서드 선언 (구현 없음)
}
interface B {
void sayHello(); // 일반 메서드 선언 (구현 없음)
}
class C implements A, B {
// 두 인터페이스의 메서드를 구현해야 함
@Override
public void sayHello() {
System.out.println("Hello from C");
}
}
public class Main {
public static void main(String[] args) {
C obj = new C();
obj.sayHello();
}
}
위는 흔히 말하는 다이아몬드 문제에 대한 해결예시이다. 만약 추상클래스였다면 컴파일단계에서 오류처리가된다.
근데 여기서 인터페이스인 A와 B를 implements한 C라는 클래스는 다중상속이 된다는건 알겠는데, 컴파일러시점에서는 뉘집자식인지 구분하는 방법에 대해 의구심이 들었다.
그러다보니 또다른 생각도 든다.
메모리의 관점에선 상속받은 메서드와 오버라이딩된 메서드도 어떻게 구분하는거지? 이름이 같은데?
그래서 찾아보았다!
그 이유는 객체 안에 가상 함수 테이블(vtable)의 주소가 저장되어 있기 때문이다.
가상함수
- 다형성 지원
- 재정의(오버라이딩) 가능
- 가상함수테이블 사용
자바의 모든 메서드는 다형성을 지원하기위해 기본적으로 가상(virtual)메서드이다. 메서드는 가상 메서드 테이블(vtable)이라는 구조를 통해 관리된다. vtable은 객체가 어떤 메서드를 호출해야 하는지에 대한 정보를 가지고 있는 테이블이다.
객체가 생성될 때, 각 클래스마다 vtable이 생성되고, 이 테이블은 클래스의 메서드에 대한 포인터를 저장한다. 인터페이스를 구현하는 클래스는 각 인터페이스의 메서드를 vtable에 포함시켜 다중 상속이 가능하도록 한다.
동일한 이름을 가진 메서드가 다중 상속되더라도 vtable을 통해 적절한 메서드가 호출된다. 메서드를 오버라이딩하면, vtable의 해당 메서드 포인터가 자식 클래스의 메서드로 업데이트되므로 부모 클래스의 메서드와 자식 클래스의 오버라이딩된 메서드를 구분할 수 있다.
정리해보자면?
개발자가 직접적으로 다룰일은 없겠지만 상속의 동작원리를 이해하기에 좋은 내용이였다 👍