다른 클래스를 작성할 때 기본이 되는 틀을 제공하면서, 다른 클래스 사이의 중간 매개 역할까지 담당하는 일종의 추상 클래스.
클래스들 사이에서 공통적인 기능을 추출하여 상속 관계를 형성하는 경우, 추상 클래스와 인터페이스는 중요한 역할을 한다. 이러한 상황에서 추상 클래스는 특정 메서드의 재정의를 강제함으로써 긍정적인 역할을 하지만, 만일 구현 클래스들이 서로 다른 기능을 가진다면 구현 메서드를 포함한다는 점에서는 한계를 가질 수 있다.
예를 들어, TV와 라디오 클래스가 공통적으로 리모콘 추상 클래스를 상속받는다고 할 때, TV 클래스에만 특화된 '인터넷 기능 사용하기' 메서드를 리모콘 추상 클래스에 포함시키면, 라디오 클래스에서 이 메서드를 상속받게 되어 오동작의 문제가 발생할 수 있다.
이러한 문제를 추상 메소드와 상수로만 구성되는 인터페이스가 해결한다. 인터페이스는 서로 관계가 없는 클래스들 사이에 관계를 맺어주는 역할을 하며, 이를 통해 더 유연하고 확장 가능한 코드 설계가 가능해진다.
또한 인터페이스를 다중 implements할 수 있으므로 다중 상속 효과를 간접적으로 얻을 수 있다.
public interface Remocon {
public static final int MAXCH=99;
int MINCH=1; // 컴파일러가 public final static
// 키워드를 컴파일 시간에 자동 삽입
public abstract void chUp();
public void chDown();
public void volUp();
void volDown(); // 컴파일러가 public abstract
// 키워드를 컴파일 시간에 자동 삽입
접근 제어자
클래스: public이나 default
변수나 메서드: 기본적으로 public. final 키워드는 사용할 수 없다.
Java8부터 구현부가 있는 static 메서드 정의 허용. 똑같이 오버라이드할 수 없이 인터페이스명으로만 접근 가능하다.
Java8부터 구현부가 있는 default 메서드를 허용하고 해당 인터페이스를 구현하는 클래스에서 선택적으로 오버라이드할 수 있다.
Java9부터 private 메서드 허용. 이는 인터페이스 내부에서만 사용할 수 있다.
구성 상수 | 추상 메서드
final static)와 추상 메소드(abstract)로만 이루어진다. 따라서 public, static, final, abstract 키워드를 생략하여도 컴파일러가 컴파일 시간에 자동으로 생성한다.public final static을, 메소드는 public abstract를 자동으로 삽입한다.public class D extends A implements B, C {/* ... */}
package com.example.part3.interfaces;
public interface Remocon {
public static final int MAXCH=99; // static final의 키워드 순서는 상관 없음.
public int MINCH=1; /*
final static 키워드를 생략하더라도
interface 내 멤버변수는
public static final int MINCH=1;와 같음.
*/
public void chUp();
public void chDown();
public void volUp();
public void volDown();
}
public class TV implements Remocon{
private int currch=10;
@Override
public void chUp() {
currch++;
if(currch>Remocon.MAXCH){
currch=1;
}
System.out.println("TV채널이 올라감");
}
@Override
public void chDown() {
currch--;
if(currch<Remocon.MINCH){
currch=99;
}
System.out.println("TV채널이 내려감");
}
@Override
public void volUp() {
// volume up functionality
}
@Override
public void volDown() {
// volume down functionality
}
}
최대 채널, 최소 채널 등 한계를 정해야 될 때처럼, 규약(인터페이스)에서 변경할 수 없는 상수로 지정하기 위해 사용.
final 키워드는 인터페이스의 final 멤버를 상속하여도 수정하지 못하게 하기 위해서 사용된다.static 키워드는 인터페이스의 인스턴스를 생성할 수 없지만, 인터페이스를 사용하는 시점에서 메모리에 static 멤버를 올리기 위해 사용한다(인터페이스명.상수명으로 접근).하나의 인터페이스에 표준화된 상수들의 값을 선언해주면 그 인터페이스를 구현하고 있는 여러 클래스들이 관련된 상수를 사용할 수 있다.

만약 여러 일반 클래스가 implements하고 있는 인터페이스를 수정해야 할 때, static final 즉 상수인 인터페이스의 상수 멤버는 독립적이기 때문에 여럿 추가하더라도 implements하는 일반 클래스에 영향을 주지 않는다.
그러나 추상 메소드를 새로 생성하게 되면 반드시 오버라이딩하게 되어 있는 일반 클래스들에 연쇄적 수정이 발생한다.
따라서 Java 8부터 인터페이스의 메소드에 static 키워드를 사용할 수 있고 default 메서드를 사용할 수 있다(접근 제어자의 의미로서 default와 다른 의미로, 메소드에 기본 구현을 제공하는 목적으로 default 키워드를 사용).
default 메소드는 추상 메소드의 기본적인 구현을 제공하는 메서드로, 오버라이드할 필요가 있다면 오버라이드하고, 그렇지 않으면 오버라이드할 필요가 없는 메소드가 아니다.
따라서 인터페이스에 디폴트 메서드가 새로 추가되어도 해당 인터페이스를 구현한 클래스는 그 메소드를 상속받으므로 오류 없이 새 디폴트 메소드를 사용할 수 있다.
Example interface{
/*public*/ default void iamDefault(){}
}
디폴트 메소드 앞에는 default 키워드를 선언해 줘야 한다(생략 불가능).
추상 메소드가 아니기 때문에 구현부를 표현하기 위해 {} 중괄호가 사용된다.
디폴트 메소드의 접근 지정자는 public이다(생략 가능하다).
static 키워드를 선언한 메소드도 구현부가 있으므로 오버라이드할 필요가 없다. 따라서 같은 맥락으로 자유롭게 수정할 수 있으며 인터페이스명.static메소드명()으로 호출할 수 있다. 그러나 static이므로 오버라이딩이 불가능하다.
Java9부터 추가된 인터페이스 내 private 메소드는 인터페이스 내부에서만 사용할 수 있는 일종의 도우미 메서드다. 인터페이스 내에서 코드 중복을 줄이고, default나 static 메소드를 생성할 때 호출되어 보다 효율적으로 코드를 재사용할 목적으로 허용되었다.
default, static, private 메소드 사용으로 인터페이스는 좀 더 유연하고 다양한 용도로 사용할 수 있게 되었다.
