개발/Java

Java에서의 다중상속

ju_ni_ 2023. 7. 19. 09:54
반응형

다중 상속이란 하나의 클래스가 두 개 이상의 부모 클래스로부터 상속을 받는 것을 의미합니다. 그러나 JAVA는 모호성 때문에 다중 상속을 지원하지 않습니다. 그렇다면 무슨 모호성 때문일까요?

 

 

모호성 문제

 

하나의 클래스가 여러 부모를 상속 받을 때, 부모 클래스 간에 동일한 이름의 필드나 메소드가 있다면, 어떤 부모 클래스의 필드 또는 메소드인지 알 수 없는 문제가 발생합니다.

 

예를 들어, 클래스 AB가 각각 int형 변수 data를 가지고 있고, 클래스 ChildAB를 상속받는다면 다음과 같은 상황이 발생합니다.

 

class A { int data = 100; }
class B { int data = 200; }

class Child extends A, B {}   // JAVA에서는 이 문법 자체가 허용되지 않습니다.

Child ch = new Child();
ch.data;   // A의 data인지 B의 data인지 판별할 수 없습니다.

 

 

모호성 해결 방법

 

그렇다면 이 모호성 문제는 어떻게 해결할 수 있을까요? 상황에 따라 다르겠지만, 일반적으로는 다음 두 가지 방법이 있습니다.

 

상황1: 두 개의 인터페이스 내에 같은 이름과 매개변수의 메소드가 선언되어 있다.

해결: 자식 클래스에서 재정의하여 사용합니다.

 

상황2: 부모 클래스의 메소드와 인터페이스의 디폴트 메소드의 이름, 매개변수가 같다.

해결: 부모 클래스의 메소드가 사용됩니다.

 

 

인터페이스와 다중상속

 

위에서 JAVA가 클래스 기반의 다중 상속을 지원하지 않는다고 했지만, 인터페이스를 통해서는 다중 상속이 가능합니다. 그 이유는 무엇일까요?

 

인터페이스의 메소드는 모두 추상 메소드이므로, 선언부만 있고 구현부가 없습니다. 만약 두 개의 인터페이스가 같은 이름과 같은 매개변수 개수의 메소드를 가지고 있어도, 두 개의 인터페이스를 모두 구현한 클래스에서는 해당 메소드를 재정의하기 때문에 충돌이 나지 않습니다.

 

interface Interface1 {
    void print();
}

interface Interface2 {
    void print();
}

class Child implements Interface1, Interface2 {
    @Override
    public void print() {
        System.out.println("이것은 Child 클래스의 print 메소드입니다.");
    }
}

public class Main {
    public static void main(String[] args) {
        Child ch = new Child();
        ch.print();  // "이것은 Child 클래스의 print 메소드입니다." 출력
    }
}

 

위의 예제에서, Interface1Interface2 둘 다 print라는 메소드를 가지고 있지만, Child 클래스는 해당 메소드를 재정의하여 사용하므로 충돌 없이 동작합니다.

 

 

Default 메소드 (인스턴스 메소드)

 

JDK 1.8 버전부터는 인터페이스에 default 메소드 선언이 가능합니다. 인터페이스를 구현한 클래스들이 있을 때, 인터페이스에 새로운 메소드를 추가하게 되면 기존에 구현한 클래스들도 모두 새로 추가한 메소드를 구현해야 하는 문제가 발생합니다. 하지만 디폴트 메소드는 구현부가 있기 때문에 기존에 구현한 클래스들에게 영향을 끼치지 않습니다. 인터페이스에서 디폴트 메소드를 사용할 경우 꼭 default 키워드를 붙여야 합니다.

 

interface MyInterface {
    default void defaultMethod() {
        System.out.println("이것은 MyInterface의 디폴트 메소드입니다.");
    }
}

class MyClass implements MyInterface {
    // 디폴트 메소드를 구현하지 않아도 컴파일 에러가 발생하지 않습니다.
}

public class Main {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.defaultMethod();  // "이것은 MyInterface의 디폴트 메소드입니다." 출력
    }
}

 

이 예제에서, MyInterfacedefaultMethod라는 디폴트 메소드가 있습니다. MyClassMyInterface를 구현하고 있지만 defaultMethod를 구현하지 않았습니다. 그럼에도 불구하고 MyClass의 인스턴스에서 defaultMethod를 호출할 수 있습니다. 이는 디폴트 메소드가 이미 인터페이스에 구현되어 있기 때문입니다. 이러한 특성 덕분에 기존에 인터페이스를 구현하던 클래스들이 인터페이스의 변경에 따른 영향을 최소화할 수 있게 됩니다.

 

 

다중 상속과 인터페이스, 그리고 디폴트 메소드에 대해 살펴보았습니다. 이러한 개념들을 잘 이해하고 활용하면 더 효과적인 프로그래밍이 가능해집니다. 추상 클래스와 인터페이스를 적절히 활용하면서 코딩의 유연성을 높일수 있습니다.

반응형