[Java] 인터페이스(Interface)
인프런 얄코의 제대로 파는 자바 강의를 듣고 정리한 글입니다.
인터페이스 정의
객체의 인스턴스 메소드를 사용할 때
개발자가 그 객체의 내부 구현을 몰라도 사용할 수 있도록 해주는 상호작용의 기능이다.
예를 들어
1
2
3
4
5
6
7
List<Student> students = new ArrayList<>();
students.add(new Student(100, "홍길동"));
students.add(new Student(999, "아무개"));
students.add(new Student(22, "임꺽정"));
// ⚠️ Comparable 적용을 하지 않으면 컴파일에러 발생
Collections.sort(students);
사용자가 정의한 클래스의 객체들에 sort 메소드를 사용하여 정렬하고 싶다면
1
2
3
4
5
6
7
8
9
10
11
class Student implements Comparable<Student> {
int id;
// ...
@Override
public int compareTo(Student o) {
return this.id - o.id; // 오름차순 정렬
}
// ...
}
Comparable 인터페이스를 적용하여 compareTo 메소드를 재정의해주면
우리는 sort 라는 메소드의 내부 구현이 어떻게 되어있는지 모르더라도
정렬이라는 기능을 편하게 사용할 수 있게 되는 것이다.
추상 클래스와의 차이
🔴 : 추상 클래스 / 🔷 : 인터페이스
- 🔴 포유류
- 북극곰 - 🔷 사냥, 🔷 수영
- 날다람쥐 - 🔷 비행
- 🔴 파충류
- 거북 - 🔷 수영
- 날도마뱀 - 🔷 사냥, 🔷 수영, 🔷 비행
- 🔴 조류
- 독수리 - 🔷 사냥, 🔷 비행
- 펭귄 - 🔷 사냥, 🔷 수영
| 추상 클래스 | 인터페이스 | |
|---|---|---|
| 기본 개념 | 물려 받는 것 (혈통/가문/계열) | 장착하는 것 (학위/자격증) |
| 다중 적용 | 불가 (모회사는 하나 뿐) | 가능 (학위는 여럿 딸 수 있음) |
| 상속관계에 의한 제한 | 있음 | 없음 |
| 생성자 | 가짐 | 가지지 않음 |
| 메소드 | 구상, 추상 모두 가능 | 추상(abstract ❌), default 구상 메소드, 클래스 메소드 |
| 필드 | 모두 가능 | 상수만 가능(final 명시 ❌) |
| 적용 연산자 | extends | implements |
예제1️⃣
추상 클래스
Mammal.java
1
2
3
4
5
6
7
public abstract class Mammal {
public boolean hibernation;
public Mammal(boolean hibernation) {
this.hibernation = hibernation;
}
}
Reptile.java
1
2
3
4
5
public abstract class Reptile {
public boolean isColdBlooded () {
return true;
}
}
Bird.java
1
2
3
4
5
public abstract class Bird {
public void reproduce () {
System.out.println("알 낳기");
}
}
인터페이스
Hunter.java
1
2
3
4
public interface Hunter {
String position = "포식자"; // ⭐️ final - 초기화하지 않을 시 오류
void hunt ();
}
Flyer.java
1
2
3
4
public interface Flyer {
String aka = "날짐승"; // ⭐️ final - 초기화하지 않을 시 오류
void fly ();
}
Swimmer.java
1
2
3
public interface Swimmer {
void swim();
}
클래스
PolarBear.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PolarBear extends Mammal implements Hunter, Swimmer {
public PolarBear() {
super(false);
}
@Override
public void hunt() {
System.out.println(position + ": 물범 사냥");
}
@Override
public void swim() {
System.out.println("앞발로 수영");
}
}
GlidingLizard.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class GlidingLizard extends Reptile implements Hunter, Swimmer, Flyer {
@Override
public void fly() {
System.out.println("날개막으로 활강");
}
@Override
public void hunt() {
System.out.println(position + ": 벌레 사냥");
}
@Override
public void swim() {
System.out.println("꼬리로 수영");
}
}
Eagle.java
1
2
3
4
5
6
7
8
9
10
11
public class Eagle extends Bird implements Hunter, Flyer {
@Override
public void fly() {
System.out.println("날개로 비행");
}
@Override
public void hunt() {
System.out.println(position + ": 토끼 사냥");
}
}
메인
Main.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// ⭐ 다형성
PolarBear polarBear = new PolarBear();
Mammal mammal = polarBear;
Swimmer swimmer = polarBear;
GlidingLizard glidingLizard = new GlidingLizard();
Eagle eagle = new Eagle();
Hunter[] hunters = {
polarBear, glidingLizard, eagle
};
// 💡 인터페이스 역시 다형성에 의해 자료형으로 작용 가능
for (Hunter hunter : hunters) {
hunter.hunt();
}
- 인터페이스는 다수 적용이 가능하다.
- 필드는
public static final- 명시할 필요 없음
- 초기화 필수 (생성자가 없기 때문)
- 메소드는
public abstract- 명시할 필요 없음
- 메소드는 적용 클래스에서 구현 필수
- 인터페이스 적용 클래스 작성시 IDE 안내 이용
- 메소드 구현
예제2️⃣
자바8에 추가된 기능들
- 클래스 메소드
default구상 메소드
인터페이스
FoodSafety.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface FoodSafety {
// ⭐️
// static 제거해 볼 것
// static abstract는 역시 불가 (추상 클래스처럼)
static void announcement () {
System.out.println("식품안전 관련 공지");
}
// ⭐️
// default 제거해 볼 것
// 구상 메소드라는 것을 구분하기 위한 용도의 default (접근 제어자가 아님)
default void regularInspection () {
System.out.println("정기 체크");
}
void cleanKitchen ();
void employeeEducation ();
}
클래스
YalcoChicken.java
1
2
3
4
5
6
7
8
9
10
11
public class YalcoChicken implements FoodSafety {
@Override
public void cleanKitchen() {
System.out.println("매일 주방 청소");
}
@Override
public void employeeEducation() {
System.out.println("직원 위생 교육");
}
}
메인
Main.java
1
2
3
4
5
6
7
FoodSafety.announcement();
YalcoChicken store1 = new YalcoChicken();
store1.regularInspection();
store1.cleanKitchen();
store1.employeeEducation();
default 로 구상 메소드를 넣을 수 있도록 한 이유
- 사용되던 인터페이스에 새로운 기능을 추가해야 한다면?
- 새로운 자바 버전의 라이브러리 인터페이스에 새 기능이 추가되어야 한다면?
- 이를 적용하여 사용하던 클래스가 매우 많을 경우…
- 해당 인터페이스의 하위 클래스들을 일일이 수정하지 않아도 되도록
- 하위호환성
다중 상속 시 충돌 문제
interface에 default 함수를 구현할 수 있으니 다중 상속 시 동일한 메소드명이 있다면 충돌이 발생하여 컴파일 에러가 나는데 아래와 같이 오버라이드를 통해 해결할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
interface Animal {
default void makeSound() {
System.out.println("동물이 소리를 냅니다");
}
}
interface Howling {
default void makeSound() {
System.out.println("아울");
}
}
abstract class Dog {
void makeSound() {
System.out.println("멍멍");
}
}
class JindoDog extends Dog implements Animal, Howling {
@Override
public void makeSound() {
// 상속받은 추상클래스의 메소드를 호출
super.makeSound(); // 멍멍
// 인터페이스에 정의된 default 메소드를 명시적으로 호출하는 문법
Animal.super.makeSound(); // 동물이 소리를 냅니다
Howling.super.makeSound(); // 아울
}
}
public class Main {
public static void main(String[] args) {
JindoDog jindoDog = new JindoDog();
jindoDog.makeSound();
}
}