인터페이스
- 일종의 추상클래스
- 추상메서드와 상수만 멤버로 가질 수 있다. (일반 메서드, 멤버변수는 가질 수 없다.)
- 클래스가 설계도, 추상클래스를 미완성 설계도라고 하면 인터페이스는 기본 설계도라고 할 수 있다.
작성
1
2
3
4
interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메서드이름(매개변수목록);
}
- 모든 멤버변수는 public static final이어야 하며, 이를 생략할 수 있다.
- 모든 메서드는 public abstract이어야 하며, 이를 생략할 수 있다.
- 단 static 메서드와 디폴트 메서드는 예외(JDK1.8부터 추가 가능하기 때문)
인터페이스에 정의된 모든 멤버에 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있다. (생략된 제어자는 컴파일 시 컴파일러가 자동으로 추가해준다.)
상속
- 인터페이스는 인터페이스로부터만 상속받을 수 있다.
- 다중상속이 가능하다. (여러 개 인터페이스로부터 상속받는 것)
1
2
3
4
5
6
7
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
interface Fightable extends Movable, Attackable {}
구현
인터페이스 그 자체로는 인스턴스를 생성할 수 없다.
클래스에서 인터페이스를 구현해야 한다.
implements
키워드 사용
1 2 3
class 클래스이름 implements 인터페이스이름 { // 인터페이스에 정의된 추상메서드를 구현해야 한다. }
인터페이스의 메서드 중 일부만 구현한다면 추상클래스로 선언해야 한다.
abstract
키워드 사용
1 2 3
abstract class 클래스이름 implements 인터페이스이름 { }
상속과 구현을 동시에 할 수 있다.
1 2 3
class 클래스이름 extends 조상클래스이름 implements 인터페이스이름 { }
메서드를 구현할 때(오버라이딩) 조상의 메서드보다 넓은 범위의 접근제어자를 지정해야 한다.
- 인터페이스 메서드의 생략된 제어자는
public abstract
이므로 제어자가 생략되어 있을 경우 반드시public
으로 해야한다.
- 인터페이스 메서드의 생략된 제어자는
인터페이스의 특징
다중상속
자바도 인터페이스를 이용하면 다중상속이 가능하다
- 두 조상으로부터 상속을 받으면 어느 조상의 것을 상속받게 되는 것인지 알 수 없어서 이름이 충돌하지 않도록 조상클래스를 변경할 수 밖에 없다. 그래서 다중상속은 장점도 있지만 단점이 더 크다고 판단하여 허용하지 않는다.
- 인터페이스로 다중상속이 가능하지만 구현하는 경우는 거의 없다.
만일 두 개의 클래스로부터 상속을 받아야 할 상황이라면
두 조상클래스 중 비중이 높은 쪽을 상속받고 다른 한쪽의 메서드와 일치하는 추상메서드를 가진 인터페이스를 작성하고, 그 인터페이스를 구현하도록 한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// AClass ... public class BClass { public void BMethod() { } } public interface BInterface { public void BMethod(); } public class AB extends AClass implements BInterface { BClass bclass = new BClass(); public void BMethod() { bclass.BMethod(); // 코드를 작성하는 대신 BClass 인스턴스의 메서드를 호출한다. } }
다형성
- 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있다.
- 인터페이스 타입으로 형변환도 가능하다.
1
2
3
// 인터페이스 Fightable을 클래스 Fighter가 구현했을 때
Fightable f = (Fightable)new Fighter();
Fightable f = new Fighter();
메서드의 매개변수 타입으로 인터페이스가 사용될 수 있다.
- 메서드 호출 시 해당 인터페이스를 구현한 클래스의 인스턴스를 매개변수로 넘겨야 한다.
1
void attack(Fightable f) {}
메서드의 리턴타입으로 인터페이스가 사용될 수 있다.
- 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환해야한다.
1 2 3 4
Fightable method() { Fighter f = new Fighter(); return f; }
인터페이스의 장점
개발시간을 단축시킬 수 있다.
일단 인터페이스가 작성되면, 이를 사용해서 프로그램을 작성하는 것이 가능하다.
표준화가 가능하다.
기본 틀을 인터페이스로 작성한 다음, 다른 개발자들이 인터페이스를 구현하여 프로그램을 작성하게 하면 일관되고 정형화된 프로그램 개발이 가능하다.
서로 관계없는 클래스들에게 관계를 맺어줄 수 있다.
서로 아무 관계 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하게 해서 관계를 맺어줄 수 있다.
독립적인 프로그래밍이 가능하다.
인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제구현에 독립적인 프로그램을 작성하는 것이 가능하다.
인터페이스의 이해
- 클래스를 사용하는 쪽(User)과 클래스를 제공하는 쪽(Provider)이 있다.
- 메서드를 사용(호출)하는 쪽(User)에서는 사용하려는 메서드(Provider)의 선언부만 알면 된다.(내용은 몰라도 된다.)
디폴트 메서드, static 메서드
JDK 1.8부터 인터페이스에 디폴트 메서드와 static 메서드를 추가할 수 있게 되었다.
static 메서드
- static 메서드는 인스턴스와 관계 없는 메서드여서 추가하지 못할 이유가 없었지만, 자바를 쉽게 배울 수 있도록 규칙을 단순히 할 필요가 있어서 인터페이스의 모든 메서드는 추상메서드여야 했다. 덕분에 static메서드는 별도의 클래스에 따로 두어야 했다.
- 대표적인 예, java.util.Collections 인터페이스 이 인터페이스와 관련된 static메서드들이 인터페이스에는 추상 메서드만 선언할 수 있다는 원칙 때문에 별도의 Collections라는 클래스에 들어가게 되었다. 만일 static 메서드를 추가할 수 있었다면 Collections클래스는 존재하지 않았을 것이다.
- 인터페이스의 static 메서드 역시 접근 제어자가 항상 public이며, 생략할 수 있다.
디폴트 메서드
추상 메서드의 기본적인 구현을 제공하는 메서드 👉 추상 메서드가 아니기 때문에 디폴트 메서드가 새로 추가되어도 해당 인터페이스를 구현한 클래스를 변경하지 않아도 된다.
구현
- 키워드
default
- 추상 메서드와 달리
몸통 {}
이 있어야 한다.
1
2
3
4
interface MyInterface {
void method();
default void newMethod(){}
}
새로 추가된 디폴트 메서드가 기존의 메서드와 이름이 중복되어 충돌하는 경우가 발생할 수 있다. 👉 충돌을 해결하는 규칙
- 여러 인터페이스의 디폴트 메서드 간의 충돌 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.
- 디폴트 메서드와 조상 클래스의 메서드 간의 충돌 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.
출처📎
- 자바의 정석