반응형

자바를 공부하다 보면 클래스 상속(extends)과 인터페이스 구현(implements)의 차이를 공부하면서 이런 차이점을 접하게 됩니다.

인터페이스는 다중 구현이 가능하지만, 클래스 상속은 단 하나의 클래스만 상속할 수 있다.

자, 처음 개념을 접할 때는 그냥 그런가 보다.. 하고 넘어갈 수 있습니다만 어느 정도 자바를 숙지하고 나면 의문점이 들 수 있습니다.

도대체 왜..? 안 될 이유가 뭐가 있지?

누군가는 이 이유를 놓고서 하늘 아래 두 부모를 두지 않는다는 서정적인 감성으로 해석하시기도 하지만, 사실 자바에서 다중 상속을 허용하지 않는 이유는 문법적인 한계 때문입니다.

지금부터 다중 상속의 가장 대표적인 문제로 꼽히는 다이아몬드 문제(Diamond Problem)을 통해서 그 이유에 대해 살펴보겠습니다.

Diamond Problem

만약 자바에서 다중 상속을 허용한다고 가정한다면, 위 그림과 같은 형태(다이아몬드)로 상속이 가능할 겁니다. 만약 이때, Person 클래스가 추상 클래스(Abstract class)이고 Father 클래스나 Mother 클래스가 Person에 대한 구현 객체라면 문제가 발생할 수 있습니다.

간단한 코드를 통해 그 상황을 살펴보겠습니다.

Person class

public abstract class Person {

	public abstract void speak();
}

Father class

public class Father extends Person {
	
	@Override
	public void speak(){
		System.out.println("speak implementation of Father");
	}
}

Mother class

public class Mother extends Person {
	
	@Override
	public void speak(){
		System.out.println("speak implementation of Mother");
	}
}

Child class

public class Child extends Father, Mother {

	public void test(){
		// calling super class method
		speak();
	}
}

위 코드는 자바에서 다중 상속을 허용한다는 가정 하에 작성한 코드입니다. 실제로는 Child 클래스에서 Father 클래스와 Mother 클래스를 동시에 상속할 수 없습니다.

자, 위 경우 Child의 내부의 test() 메소드를 실행하게 된다면 Child 객체는 상위 객체로부터 상속받은 speak() 메소드를 실행해야 하는데 Abstract method로 정의된 speak() 메소드를 Father 클래스에서도 구현했고, Mother 클래스에서도 구현했기에 어떤 speak() 메소드를 호출해야 할지 자식은 알 수 없습니다.

이처럼 자바에서 다중 상속을 허용하지 않는 이유는 바로 이런 다이아몬드 문제가 발생할 수 있기 때문인데요. 그렇기 때문에 자바 개발자는 multiple inheritance가 필요할 경우 인터페이스의 다중 상속을 이용해야 합니다. 인터페이스로 한다면 아래와 같은 코드 작성이 가능합니다.

A interface

public interface A {

    public void foo();
}

B interface

public interface B {

    public void foo();
}

C interface

public interface C extends A, B {
	// A와 B 인터페이스에서 구현된 foo() 메소드
    public void foo();
}

위와 같은 코드는 가능합니다. 즉, 인터페이스는 다중 상속이 허용 되고 클래스는 허용되지 않는 것이지요.

그렇다면 왜 인터페이스는 가능할까요?

그건 바로 인터페이스는 실질적인 구현이 이루어지지 않고 메소드에 대한 정의만 하고 있기 때문입니다. 결국엔 메소드가 겹치더라도 최종 구현 부분은 구현 객체(Concrete class)에서 이루어질 것이기 때문에 위와 같은 코드가 전혀 문제없게 됩니다.

잘 이해가 가지 않으시는 분은 위 예제에서 작성한 interface C에 대한 구현 객체를 만들어 실행해보시면 이해가 가실겁니다.

반응형
반응형