티스토리 뷰

주의 사항!

  • 이 글은 제가 직접 공부하는 중에 작성되고 있습니다.
  • 따라서 제가 이해하는 그대로의 내용이 포함됩니다.
  • 따라서 이 글은 사실과는 다른 내용이 포함될 수 있습니다.


디폴트 메서드는 모든 구현 객체에서 공유하는 기본 메서드처럼 보이지만, 사실은 인터페이스에서 디폴트 메서드를 허용한 다른 이유가 있습니다.

 

디폴트 메서드의 필요성

인터페이스에서 디폴트 메서드를 허용한 이유는 기존 인터페이스를 확장해서 새로운 기능을 추가하기 위함입니다. 기존 인터페이스의 이름과 추상 메서드의 변경 없이 디폴트 메서드만 추가할 수 있기 때문에 이전에 개발한 구현 클래스를 그대로 사용할 수 있으면서 새롭게 개발하는 클래스는 디폴트 메서드를 활용할 수 있습니다.

 

기존에 MyInterface라는 인터페이스와 이를 구현한 MyClassA라는 클래스가 있었습니다. 시간이 흘러 MyInterface에 기능을 추가해야 할 필요성이 생겼습니다. 그래서 MyInterface에 추상 메서드를 추가했는데, 엉뚱하게도 MyClassA에서 문제가 발생합니다. 그 이유는 추가된 추상 메서드에 대한 실체 메서드가 MyClassA에 없기 때문입니다(인터페이스에 선언된 추상 메서드를 구현 클래스에서 실체 메서드로 정의하지 않으면 해당 클래스는 추상 클래스가 되어버립니다). MyClassA를 수정할 여건이 안 된다면 결국 MyInterface에 추상 메서드를 추가할 수 없습니다. 그래서 MyInterface에 디폴트 메서드를 선언합니다. 디폴트 메서드는 추상 메서드가 아니기 때문에 구현 클래스에서 실체 메서드를 작성할 필요가 없습니다. 따라서 MyClassA는 아무런 문제 없이 계속 사용이 가능합니다.

 

여기에 새로운 구현 클래스 MyClassB를 추가할 때도 인터페이스에 추상 메서드로 선언된 메서드는 모두 실체 메서드로 정의해야 하지만 디폴트 메서드는 인터페이스에 정의된 것을 그대로 사용해도 되고, 필요에 따라 이를 오버 라이딩해서 사용할 수도 있습니다. 

 

(즉, 인터페이스를 작성할 때, 이 인터페이스의 구현 클래스들이 반드시 가져야 하는 메서드로 생각되고, 또 구현 클래스마다 실행 내용이 달라져야 한다면 추상 메서드로 작성하는 것이 용이해 보이고, 몇몇 구현 클래스들은 이 메서드를 가지지 않을 것으로 생각되거나, 대부분의 구현 클래스들이 동일한 내용의 메서드를 가질 것으로 예상될 경우에는 디폴트 메서드로 작성하는 것이 용이해 보입니다.)

 

디폴트 메서드가 있는 인터페이스 상속

부모 인터페이스에 디폴트 메서드가 정의되어 있을 경우, 자식 인터페이스에서 디폴트 메서드를 활용하는 방법은 다음 세 가지가 있습니다.

  • 디폴트 메서드를 단순히 상속만 받는다.
  • 디폴트 메서드를 오버 라이딩해서 실행 내용을 변경한다.
  • 디폴트 메서드를 추상 메서드로 재 선언한다.

 

다음과 같이 추상 메서드와 디폴트 메서드가 선언된 ParentInterface가 있다고 가정해 보겠습니다.

public interface ParentInterface
{
	void method1();
	default void method2() { ... }
}

다음 ChildInterface1은 ParentInterface를 상속하고 자신의 추상 메서드인 method3()를 선언합니다.

public interface ChildInterface1 extends ParentInterface 
{
	void method3();
}

이 경우 ChildInterface 인터페이스를 구현하는 클래스는 method1()과 method3()의 실체 메서드를 가지고 있어야 하며, ParentInterface의 method2()를 호출할 수 있습니다.

public class ClassName implements ChildInterface
{
	@Override
	public void method1() { ... }
    
	@Override
	public void method3() { ... }
}
ChildInterface ci1 = new ClassName();
ci1.method1();
ci1.method2();
ci1.method3();

다음 ChildInterface2는 ParentInterface를 상속하고 ParentInterface의 디폴트 메서드인 method2()를 오버 라이딩합니다. 그리고 자신의 추상 메서드인 method3()를 선언합니다.

public interface ChildInterface2 extends ParentInterface
{
	@Override
	default void method2() { ... }

	void method3();
}

이 경우도 ChildInterface2 인터페이스를 구현하는 클래스는 method1()과 method3()의 실체 메서드를 가지고 있어야 하며, ChildInterface2에서 오버 라이딩한 method2()를 호출할 수 있습니다.

public class ClassName2 implements ChildInterface
{
	@Override
	public void method1() { ... };

	@Override
	public void method3() { ... };
}
ChildInterface2 ci2 = new ClassName();
ci2.method1();
ci2.method2();
ci3.method3();

다음 ChildInterface3는 ParentInterface를 상속하고 ParentInterface의 디폴트 메서드인 method2()를 추상 메서드로 재 선언합니다. 그리고 자신의 추상 메서드인 method3()를 선언합니다.

public interface ChildInterface3 extends ParentInterface
{
	@Override
	void method2();    //추상 메서드로 재선언

	void method3();
}

이 경우 ChildInterface3 인터페이스를 구현하는 클래스는 method1()과 method2(), method3()의 실체 메서드를 모두 가지고 있어야 합니다.

public class ClassName3 implements ChildInterface3
{
	@Override
	public void method1() { ... }
    
	@Override
	public void method2() { ... }
    
	@Override
	public void method3() { ... }
}
ChildInterface3 ci3 = new ClassName3();
ci3.method1();
ci3.method2();
ci3.method3();

 

공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
TAG
more
«   2024/12   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
글 보관함