자바의 인터페이스에 대해 학습하기
🤔 인터페이스가 메소드에 대한 구현까지할 수 있다고? 그러면 추상클래스랑 똑같은 거 아님?
- 추상클래스는
is a
개념이다.
- 예) 추상클래스 - 컴퓨터(
Computer
), 추상클래스를 상속한 클래스 - 노트북(Notebook
)
- 노트북은 컴퓨터이다.
- 즉, 노트북은 컴퓨터(데스크탑, 노트북 등) 중 하나이다.
- 노트북은 컴퓨터 계열이므로 또 다른 추상클래스인 세탁기(
Washer
)를 상속받을 수 없다.- 인터페이스는
has a
개념이다.
- 예) 인터페이스 - 코딩 가능(
Developable
), 인터페이스를 구현한 클래스 - 홍길동
- 홍길동은 코딩할 수 있다.
- 즉, 홍길동의 능력중 하나가 코딩인 것이다.
- 인터페이스는 기능을 의미하므로 인터페이스의 이름에는
able
로 끝나는 것들이 많다.- 홍길동은 또 다른 인터페이스인 요리(C
ookable
)도 구현하여 코딩뿐만 아니라 요리도 할 수 있는 등의 여러가지 능력을 가질 수 있다.
접근제어자 interface 인터페이스명 {
(public static final) 타입 상수명 = 값;
(public abstract) 리턴타입 메소드명(파라미터...);
static 리턴타입 메소드명(파라미터...) {...}
default 리턴타입 메소드명(파라미터...) {...}
}
public
, default
public static final
이어야 하며, 이를 생략시 컴파일러가 자동으로 추가해준다.public
으로 설정해야 함을 잊지말자.public static
이어야 하며, 이를 생략시 컴파일러가 자동으로 추가해준다.public
으로 설정해야 함을 잊지말자.: 인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중 상속이 가능하다.
인터페이스의 추상 메소드는 구현부가 없어, 여러 인터페이스의 추상 메소드를 상속받아도 구현부가 없는 사실은 같기 때문에 다중 상속이 가능하다.
부모 인터페이스의 멤버를 모두 상속받는다.
예제
interface Movable { // 이동할 수 있는 기능
void move(int x, int y); // 지정된 위치(x, y)로 이동하는 메소드
}
interface Attackable { // 공격할 수 있는 기능
void attack(Unit u); // 지정된 유닛을 공격하는 메소드
}
interface Fightable extends Movable, Attackable {} // 싸울 수 있는 기능 <- 이동 / 공격 가능
🤔 클래스에서 두 인터페이스를 구현하였는데, 두 인터페이스에 메소드 시그니처가 동일한 디폴트 메소드가 존재한다면?
: 구현 클래스에서 중복되는 인터페이스의 디폴트 메소드를 재정의하여 사용한다.
- 재정의하지 않으면 컴파일 에러가 발생한다.
- 스태틱 메소드가 아니므로 참조할 수 있는 방법이 아래와 같다.
인터페이스.super.디폴트메서드()
interface JoinMember { default void preJoin() { System.out.println("pre member"); } } interface JoinGroup { default void preJoin() { System.out.println("pre group"); } } class Member implements JoinMember, JoinGroup { @Override public void preJoin() { JoinMember.super.preJoin(); JoinGroup.super.preJoin(); } }
: 추상 클래스와 마찬가지로 인터페이스 그 자체로 인스턴스를 생성할 수 없으므로 반드시 구현 클래스를 생성한 후 사용한다.
문법
class 클래스명 implements 인터페이스1, 인터페이스2, ... {
// 인터페이스의 추상 메소드를 구현한다.
}
예제
class Unit {
int currentHP; // 현재 체력
int x;
int y;
}
interface Movable { // 이동할 수 있는 기능
void move(int x, int y); // 지정된 위치(x, y)로 이동하는 메소드
}
interface Attackable { // 공격할 수 있는 기능
void attack(Unit u); // 지정된 유닛을 공격하는 메소드
}
interface Fightable extends Movable, Attackable {} // 싸울 수 있는 기능 <- 이동 / 공격 가능
class Figther extends Unit implements Fightable {
@Override
public void move(int x, int y) { ... }
@Override
public void attack(Unit u) { ... }
}
자바 8버전 이전
: 인터페이스와 구현 클래스 중간에 추상 클래스를 두어 인터페이스의 추상 메소드를 추상 클래스가 빈 내용으로 구현하고 구현 클래스는 해당 추상 클래스를 상속받아 원하는 메소드만 오버라이딩해 사용한다.
interface JoinMember {
void preJoin();
void afterJoin();
}
class JoinMemberAdater implements JoinMember {
@Override
void preJoin() {}
@Override
void afterJoin() {}
}
class HelloJoinMember implements JoinMemberAdater {
@Override
void preJoin() {
System.out.println("안녕하세요.");
}
}
class NotiJoinMember implements JoinMemberAdater {
@Override
void afterJoin() {
System.out.println("멤버용 새 글이 올라왔어요.");
}
}
자바 8버전부터
: 구현 클래스는 인터페이스의 디폴트 메소드를 재정의하여 사용한다.
interface JoinMember {
default void preJoin() {}
default void afterJoin() {}
}
class HelloJoinMember implements JoinMember {
@Override
void preJoin() {
System.out.println("안녕하세요.");
}
}
class NotiJoinMember implements JoinMember {
@Override
void afterJoin() {
System.out.println("멤버용 새 글이 올라왔어요.");
}
}
: 오직 하나의 객체만을 생성할 수 있는 일회용 클래스이며, 따로 소스 파일을 생성하여 클래스를 선언할 필요가 없다.
클래스의 선언과 객체의 생성을 동시에 한다.
이름이 없기 때문에 생성자를 가질 수 없다.
익명 클래스를 컴파일하면 외부 클래스명$숫자.class
의 형식으로 클래스파일명이 결정된다.
문법
인터페이스명 변수명 = new 인터페이스명() {
// 인터페이스의 추상 메소드 구현
}
조상클래스명 변수명 = new 조상클래스명() {
}
예제
interface Movable { // 이동할 수 있는 기능
void move(int x, int y); // 지정된 위치(x, y)로 이동하는 메소드
}
interface Attackable { // 공격할 수 있는 기능
void attack(Unit u); // 지정된 유닛을 공격하는 메소드
}
interface Fightable extends Movable, Attackable {} // 싸울 수 있는 기능 <- 이동 / 공격 가능
Fightable fighter = new Fightable() {
@Override
public void move(int x, int y) { ... }
@Override
public void attack(Unit u) { ... }
}
: 인터페이스 레퍼런스는 다형성을 통해 인터페이스를 구현한 클래스의 인스턴스를 참조할 수 있다.
: 오직 인터페이스 내부에서만 사용할 수 있는 구현부를 가진 메소드
public
접근제어자로 인해 인터페이스 구현 클래스가 해당 메소드를 필요로하지않아도 반드시 상속받게 된다.private
메소드와 static private
메소드가 존재한다.Reference
- 자바의 정석 3rd Edition, 남궁성 지음
- 인터페이스