
상속은 객체 지향 프로그래밍의 중요한 개념 중 하나로,
기존 클래스(부모 클래스)의 특성과 기능을 새로운 클래스(자식 클래스)가 물려받아 재사용하거나 확장하는 것을 의미한다.
상속은 코드의 재사용성을 높이고, 유지 보수를 쉽게 하며, 객체 간의 계층 구조를 형성할 수 있게한다.
또한 상속을 통해 객체의 타입을 부모 클래스 타입으로 다룰 수 있어,
하나의 객체가 여러 가지 형태를 가질 수 있는 다형성을 지원한다.
클래스는 오직 하나의 부모 클래스로부터만 상속을 받을 수 있다.
다이아몬드 문제는 객체 지향 프로그램에서 다중 상속을 지원할 때 발생할 수 있는
상속의 모호성 문제를 의미한다.
자식 클래스가 여러 부모 클래스로부터 상속을 받을 때
동일한 이름과 시그니처의 메서드 또는 속성이 여러 부모 클래스에 존재하는 경우
자식 클래스가 어느 부모의 메서드나 속성을 상속받아야할 지 모호해지는 상황에서 발생한다.
클래스는 여러 개의 인터페이스를 구현(implements) 할 수 있으며, 이를 다중 상속이라고 한다.
인터페이스는 메소드의 시그니처(선언)만을 정의하고, 실제 구현은 클래스에서 제공한다.
디폴트 메서드는 인터페이스 내에서 구현부가 있는 메서드로,
인터페이스를 구현하는 클래스가 해당 메서드를 명시적으로 재정의하지 않으면
디폴트 메서드가 제공하는 기본 구현을 사용하게 된다.
인터페이스 내 메소드에 default 키워드를 사용해 구현부{}를 정의한다.
public interface MyInterface{
// 추상 메서드
void myMethod();
// 디폴트 메서드
deafault void myDefaultMethod(){
System.out.println("This is a default method.");
}
}
디폴트 메서드는 상속된 클래스나 인터페이스에서 재정의(Override)가 가능하다.
예를 들어, Class A가 Interface A, Interface C를 구현했을 때(implements),
A, B에 동일한 메소드 시그니처가 있는 상황을 가정해보자.
※ 메소드 시그니처(Method Signature)란 메소드 정의에서 메소드 이름과 파라미터 목록을 의미한다.
public interface InterfaceA{
void myMethod();
}
public interface InterfaceB{
void myMethod();
}
인터페이스 A, B가 동일한 메서드 시그니처를 가지고 있지만
Class A는 myMethod() 하나만 구현하면된다.
public class ClassA{
@Override
public void myMethod(){
System.out.println("This is a my method.");
}
}
인터페이스 A, B가 동일한 디폴트 메서드가 있는 경우 충돌이 발생할 수 있다.
구현 클래스에서 충돌을 해결하려면, 해당 메서드를 명시적으로 오버라이딩해
어느 부모 인터페이스의 메서드를 사용할지 지정해야 한다.
public interface InterfaceA{
default void myMethod(){
System.out.println("This is a B's default method.");
}
}
public interface InterfaceB{
default void myMethod(){
System.out.println("This is a C's default method.");
}
}
구현 클래스 ClassA는 myMethod()메서드를 오버라이딩하고,
A.super.myMethod()과 같이 특정 인터페이스의 default 메서드를 명시적으로 호출
public class ClassA implements InterfaceA, InterfaceB{
@Override
public void myMethod(){
// 둘 다 호출
A.super.myMethod();
B.super.myMethod();
// 또는 하나만 호출
A.super.myMethod();
}
}
충돌하는 메서드 myMethod() 대신 완전히 새로운 구현을 제공해 두 인터페이스의 충돌을 해결한다.
Class A는 A와 B의 default 메소드를 사용하지 않고, 자신만의 방식으로 새롭게 구현한다.
public class ClassA implements InterfaceA, InterfaceB{
@Override
public void myMethod(){
System.out.println("C's own implementation of myMethod");
}
}
인터페이스도 다른 인터페이스를 상속할 수 있으며, 이 경우에도 다중 상속이 가능하다.
public interface InterfaceA{
void myMethodA();
}
public interface InterfaceB{
void myMethodB();
}
public interface InterfaceC extends InterfaceA, InterfaceB{
void myMethodC();
}
하위 인터페이스(InterfaceC)를 구현하는 클래스는 하위 인터페이스의 메서드뿐만 아니라
상위 인터페이스(A,B)의 모든 추상 메소드를 구현해야 한다.
그렇기 때문에 구현 클래스로부터 객체를 생성한 뒤 상위/하위 인터페이스 타입으로 변환이 가능하다.
super 키워드를 사용해 특정 인터페이스의 메소드를 명시적으로 호출한다.