Post

[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 명시 ❌)
적용 연산자extendsimplements

예제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 로 구상 메소드를 넣을 수 있도록 한 이유

  • 사용되던 인터페이스에 새로운 기능을 추가해야 한다면?
    • 새로운 자바 버전의 라이브러리 인터페이스에 새 기능이 추가되어야 한다면?
    • 이를 적용하여 사용하던 클래스가 매우 많을 경우…
  • 해당 인터페이스의 하위 클래스들을 일일이 수정하지 않아도 되도록
    • 하위호환성

다중 상속 시 충돌 문제


interfacedefault 함수를 구현할 수 있으니 다중 상속 시 동일한 메소드명이 있다면 충돌이 발생하여 컴파일 에러가 나는데 아래와 같이 오버라이드를 통해 해결할 수 있다.

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();
    }
}