Kotlin & Java

인터페이스의 정적(static) 메서드와 기본(default) 메서드

Nanamare 2020. 3. 2. 01:58
728x90

자바 8 이전에는 인터페이스의 모든 메서드가 추상 메서드이어야 했다. 구현부가 없어야 했다.

하지만 자바 8에서부터는 구현이 있는 정적 메서드, 기본 메서드를 추가할 수 있다.

 

정적 메서드

이전 관점에서는 인터페이스를 추상적인 의미를 가진다고 생각했고, 그렇기 때문에 구현을 하는 방식은 디자인 관점에서 맞지 않았지만, 이런 사고가 다양한 개발을 거치면서 진화했다. 특히 그 중에서도 팩터리 메서드는 인터페이스와 아주 궁합이 좋다.

e.g

IntSequence 인터페이스에는 다음과 같이 주어진 정수의 숫자 시퀀스를 만들어내는 정적 메서드 digitsOf() 를 추가할 수 있다

이 메서드는 IntSequence 인터페이스를 구현한 클래스 중에서 수많은 인스턴트들이 전달 되지만, 어느 클래스의 인스턴스인지 신경쓰지 않고, 인스턴스를 만들어 낼 수 있다.

public interface IntSequence {
	// ...
    public static IntSequence digitsOf(int number) {
    	return new DigitSequence(number);
    }
}

 

기본 메서드

인터페이스에서 기본 메서드를 추가하기 위해서는 default 제어자를 붙어야한다.

// 기본적으로 interface 에 작성하는 모든 함수는 public
public interface IntSequence {
	deault boolean hasNext() {
    	return true;
    }
    int next();
}

 

기본 메서드의 중요한 용도는 인터페이스를 진화시키는 것이다. 오랜 세월 자바에 존재해온 Collection 인터페이스를 예로 살펴보자. 

가령 현재 IntSequence 클래스에서 Collection 의 stream 함수를 사용하기를 원한다고 가정해보자.

Coollection 인터페이스를 예전의 방식으로 구현한다면 다음과 같은 클래스로 구현해야한다

public class IntSequence implements Collection

자바 8 에서는 stream 메서드를 Collection 인터페이스에 추가했다

default 메서드로 추가된 stream 메서드

기본 메서드로 추가되지 않았다면, IntSequence 에서 새로운 메서드를 구현하지 않는다면 컴파일 자체가 되지 않을 것이지만, 이 문제를 default 로 해결했다. IntSequence 클래스에서 stream 메서드를 호출하면 Collection.stream 메서드가 호출된다.

 

기본 메서드의 충돌

public interface Company {
	default int getId {
    	return 0;
    }
}

public interface Employee {
	default int getId {
    	return Math.abs(hashCode());
    }
}

public class CompanyGroup implements Company, Employee {
	// ...
}

위와 같이 코딩하고 컴파일 하면 Company, Employee 클래스의 getId 함수에서 어떤 메서드를 사용할까?

정답은 당연히 컴파일러는 선택할 수 없어 메서드가 겹쳐 모호함 오류가 있다고 알려준다.

이런 문제를 해결하려면 CompanyGroup 에서 getId 함수를 오버라이드해서  고유한 ID 체계를 가지거나, 둘중 하나의 메서드로 위임해야한다.

public class CompanyGroup implements Company, Employee {
    public int getId {
    	return Employee.super.getId();
    }
}

 

그럼 Company, Employee 메서드중 하나를 default 메서드에서 추상 메서드로 변경하면 어떨까 ?

답은 컴파일러에서 위와 같은 오류를 던진다. 결국은 개발자가 이 모호함을 해결해야 한다.

728x90