반응형
자바8 인터페이스 변화
기본 메소드 (Default Methods)
- 인터페이스에 메소드 선언이 아니라 구현체를 제공하는 방법
- 해당 인터페이스를 구현한 클래스를 깨트리지 않고 새 기능을 추가할 수 있다.
- 기본 메소드는 구현체가 모르게 추가된 기능으로 그만큼 리스크가 있다.
- 컴파일 에러는 아니지만 구현체에 따라 런타임 에러가 발생할 수 있다.
- 기본 메소드가 항상 모든 상황에 동작한다는 보장이 없기 때문에 명시적으로 어떤 동작을 하는지 반드시 문서화 해야한다. (@implSpec 자바독 태그 사용)
- Object가 제공하는 기능 (equals, hasCode)는 기본 메소드로 제공할 수 없다.
- 구현체가 재정의해야 한다.
- 본인이 수정할 수 있는 인터페이스에만 기본 메소드를 제공할 수 있다.
- 인터페이스를 상속받는 인터페이스에서 다시 추상 메소드로 변경할 수 있다.
- 인터페이스 구현체가 재정의 할 수도 있다.
스태틱 메소드
- 해당 타입 관련 헬퍼 또는 유틸리티 메소드를 제공할 때 인터페이스에 스태틱 메소드를 제공할 수 있다.
인터페이스 예제
- Goo.java
public interface Goo {
void printName();
String getName();
/*
나중에 해당 인터페이스로 공통적인 기능을 제공해주었으면 좋겠다고하여 추가한 추상 메소드 : printNameUpperCase()
*/
//void printNameUpperCase(); 그러나 해당 형태로 추가하면 해당 인터페이스를 구현한 모든 클래스에서 컴파일 에러 발생
/*
java8에서 등장한 default 키워드를 이용하여 메소드를 추가하면 해당 인터페이스를 구현하는 클래스에서 메소드를 구현하지 않아도 사용 가능하다.
하지만 이 기능이 항상 모든 상황에 동작한다는 보장이 없다. 현재는 getName()에서 null을 리턴하면 런타임 에러가 발생할 수 있다.
문서화(@implSpec 자바독 태그)를 통해 이 기본 구현체가 어떤 일을하는지 명시해야한다.
인터페이스의 기본 메소드(default 메소드)의 제약사항
- Object가 제공하는 메소드(equals, hasCode 등)들은 인터페이스의 기본 메소드로 제공할 수 없다.
단, 추상 메소드로 선언하는 것은 상관이 없다.
*/
/**
* @implSpec 이 구현체는 getName()으로 가져온 문자열을 소문자로 바꿔 출력한다.
*/
default void printNameLowerCase(){
System.out.println(getName().toLowerCase());
}
/**
* @implSpec 이 구현체는 getName()으로 가져온 문자열을 대문자로 바꿔 출력한다.
*/
default void printNameUpperCase(){
System.out.println(getName().toUpperCase());
}
/*
Object가 제공하는 기본 메소드를 인터페이스의 기본 메소드로 제공하려했기에 컴파일 에러 발생
*/
//default String toString(){ }
/*
Object가 제공하는 기본 메소드이지만 추상 메소드로 선언만 하는 것은 가능하다.
다만 이는 모든 인스턴스가 오브젝트에서 구현된 것을 상속받고 있다.
이것을 사용하는 경우는 인터페이스에서 가지는 특별한 제약사항이 있을때 사용한다.
예를 들어, 이 인터페이스를 구현하는 인스턴스의 toString은 일반적인 Object의 toString과는 다르다.
*/
String toString();
/*
static 키워드를 이용하여 해당 타입과 관련하여 헬퍼 또는 유틸리티 메소드를 제공할 수 있다.
*/
static void printAnything() {
System.out.println("Goo");
}
}
- Bar.java
public interface Bar extends Goo{
/*
기존 Goo가 기본 메소드로 제공하던 void printNameUpperCase()를
Bar 인터페이스에서는 더 이상 기본 메소드로 제공하고 싶지 않을 때는 추상 메소드로 다시 선언 해준다.
*/
void printNameUpperCase();
}
- Hoo.java
public interface Hoo {
default void printNameUpperCase() {
System.out.println("HOO");
}
}
- DefaultGoo.java
/*
만약, 동일한 기본 메소드를 제공하는 인터페이스를 여러 개 구현한 경우 컴파일 에러 발생.
어떤 인터페이스의 기본 메소드를 사용해야 될지 모르기 때문이다.
이렇게 기본 메소드가 충돌하는경우는 직접 재정의(Override)해서 사용해야한다.
*/
public class DefaultGoo implements Goo, Hoo {
String name;
public DefaultGoo(String name) {
this.name = name;
}
@Override
public void printName() {
System.out.println(this.name);
}
@Override
public String getName() {
return this.name;
}
/*
인터페이스에서 기본으로 제공하는 메소드가 문제가 있을 경우
재정의(Override)하여 사용할 수 있다.
*/
@Override
public void printNameUpperCase() {
System.out.println(this.name.toUpperCase());
}
}
- Main.java
public class Main {
public static void main(String[] args){
Goo goo = new DefaultGoo("Goo");
/*
default 키워드 메소드 & 추상 메소드 : 인스턴스 사용
*/
goo.printName(); //인터페이스의 추상 메소드 구현
goo.printNameUpperCase(); //기본 메소드의 충돌이 발생하여 인터페이스의 기본 메소드 재정의
goo.printNameLowerCase(); //인터페이스의 기본 메소드
/*
static 키워드 메소드 : 해당 인터페이스 타입에서 사용
*/
Goo.printAnything(); //인터페이스의 헬퍼, 유틸리티 메소드
}
}
[참고자료]
반응형
'Java > 기본' 카테고리의 다른 글
자바 스트림(Java Stream) API - 1 (스트림 개념 소개) (0) | 2021.06.26 |
---|---|
자바 인터페이스(Java Interface) 변화 - 2 (자바8 인터페이스 구조 변화) (0) | 2021.06.24 |
자바 람다(Java Lambda) - 4 (메소드 레퍼런스) (0) | 2021.06.20 |
자바 람다(Java Lambda) - 3 (람다 표현식 사용 조건) (0) | 2021.06.17 |
자바 람다(Java Lambda) - 2 (자바 함수형 인터페이스) (0) | 2021.06.16 |