[Java] 인터페이스 (interface)

Jeini·2022년 10월 29일
0

☕️  Java

목록 보기
18/70
post-thumbnail

💡 인터페이스


👉 "이 클래스는 이런 기능들을 반드시 제공할 거야!" 라고 약속하는 설계도 같은 것

인터페이스는 abstract, final와 함께 대표적인 규제이다.
인터페이스의 역할은 이렇다. 어떤 클래스가 있고 그 클래스가 특정한 인터페이스를 사용한다면 그 객체는 반드시 인터페이스의 메서드들을 구현해야 한다.

만약 인터페이스에서 강제하고 있는 메소드를 구현하지 않으면 컴파일 조차 되지 않는다.

예시를 보자.

interface I {
    public void z(); // 중괄호 없음 비어있는 메서드 클래스에 구현함.
}
 
class A implements I { // class A 구현
    public void z() { // 이 부분이 없으면 Error
    }
}

클래스 A는 인터페이스 I를 '구현' 한다.

클래스 A 뒤의 implements I는 이 클래스가 인터페이스 I를 구현하고 있다는 의미다.
그것은 interface I의 맴버인 public void z() 메서드를 클래스 A가 반드시 포함하고 있어야 한다는 뜻이다. 따라서 위의 코드는 문제가 없다.

인터페이스와 상속은 다르다.

✔️ 인터페이스: 하위 클래스에 특정한 메서드가 반드시 존재하도록 강제(implements)
✔️ 상속: 상위 클래스의 기능을 하위 클래스가 물려 받는 것 (extends)

인터페이스는 사용하는 키워드도 다르다.
클래스를 선언 할 때는 class를 사용하지만 인터페이스는 interface를 사용한다.


✅ 인터페이스 특징

1. 메서드 규격만 정의

  • 인터페이스 안에서는 메서드의 이름, 파라미터, 리턴타입만 선언
  • 실제 동작(구현)은 인터페이스를 구현한 클래스에서 작성

2. 다중 구현 가능

  • 클래스는 하나의 클래스만 상속할 수 있지만, 여러 개의 인터페이스를 구현할 수 있다
    → 다형성을 넓게 사용 가능

3. 공통 규약 제공

  • 예: List, Map, Set 같은 자바 컬렉션 인터페이스
  • 다양한 구현체(ArrayList, HashMap 등)들이 같은 규칙대로 동작

✏️ 인터페이스를 활용한 예제

// 인터페이스 정의
interface Animal {
    void sound();   // 메서드 선언 (구현 없음)
    void move();
}

// 클래스가 인터페이스 구현
class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println("멍멍");
    }

    @Override
    public void move() {
        System.out.println("강아지가 달린다!");
    }
}

class Bird implements Animal {
    @Override
    public void sound() {
        System.out.println("짹짹");
    }

    @Override
    public void move() {
        System.out.println("새가 난다!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog();
        Animal bird = new Bird();

        dog.sound();  // 멍멍
        bird.sound(); // 짹짹
    }
}

인터페이스를 이용해서 서로가 동일한 메서드를 만들도록 규약을 만들어서 공유한 결과 각자가 상대의 일정이나 구현하는 방식에 덜 영향을 받으면서 애플리케이션을 구축 할 수 있었다.

인터페이스는 어떠한 클래스가 어떠한 메서드를 가지고 있는가, 또한 어떤 멤버변수를 가지고 있느냐에 대한 명세서 같은 느낌이다.
그러면 저 계산기를 구현하고 있는 클래스들은 그 명세서에 적혀있는 대로 명세서에 정의되어 있는 대로 클래스의 멤버를 구체적으로 구현해야지만 컴파일이 되게 되는 것이다.

이렇게 함으로써, 서로간의 커뮤니케이션 미스를 방지할 수 있고 빠른 시간 내에 코드를 완성할 수 있다.

💡 인터페이스의 규칙


✔️ 하나의 클래스가 여러개의 인터페이스를 구현 할 수 있다.

클래스 A는 메소드 x나 z 중 하나라도 구현하지 않으면 오류가 발생한다.

interface I1 {
    public void x();
}
 
interface I2 {
    public void z();
}
 
class A implements I1, I2 {
    public void x() {}
    public void z() {}   
}

✔️ 인터페이스도 상속이 된다.

interface I3 {
    public void x();
}
 
interface I4 extends I3 {
    public void z();
}
 
class B implements I4 {
    public void x() {}
    public void z() {}   
}

✔️ 인터페이스의 맴버는 반드시 public이다.

interface I5 {
    private void x(); // Error
}

위 코드는 오류를 발생한다.
인터페이스는 그 인터페이스를 구현한 클래스를 어떻게 조작할 것인가를 규정한다.

그렇기 때문에 외부에서 제어 할 수 있는 가장 개방적인 접근 제어자인 public만을 허용한다.

public을 생략하면 접근 제어자 default가 되는 것이 아니라 public이 된다. 왜냐하면 인터페이스의 맴버는 무조건 public이기 때문이다.

💡 interface vs abstract


인터페이스와 추상 클래스는 서로 비슷한 듯 다른 기능이다.

✔️ 인터페이스
: 클래스가 아닌 인터페이스라는 고유한 형태를 지님
: 구체적인 로직이나 상태를 가지고 있을 수 없음
(아예 그냥 추상 메서드로!)
: 멤버 변수를 두지 않고 메서드로만 남기고 싶을 때 많이 사용
: 다중 상속의 효과를 가질 수 있음

✔️ 추상 클래스
: 일반적인 클래스
: 구체적인 로직이나 상태를 가짐
(일부는 구현된 메서드를 가질 수 있고 일부는 추상 메서드를 가질 수 있음.)

💡 default 메서드와 static 메서드


interface Myinterface {
	void method();
    default void newMethod() {}
}
  • 인터페이스에 default 메서드, static메서드 추가 가능. (JDK1.8부터)
  • 인터페이스에 새로운 메서드(추상 메서드)를 추가하기 어려움.

    해결책 ➡️ 디폴트 메서드(default method)

  • 디폴트 메서드는 인스턴스 메서드(인터페이스 원칙 위반)

✅ default 메서드란?

  • 인터페이스 안에서도 구현이 있는 메서드를 정의할 수 있게 해주는 기능
  • default 키워드를 붙이면, 인터페이스 안에 기본 동작을 구현 가능

👉 즉, 인터페이스 = 규격만 정의 라는 제한을 완화한 것.

❗️ default 메서드가 기존의 메서드와 충돌할 때의 해결책

✔️ 여러 인터페이스의 디폴트 메서드 간의 충돌

  • 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.

✔️ default 메서드와 조상 클래스의 메서드 간의 충돌

  • 조상 클래스의 메서드가 상속되고 (우선권), 디폴트 메서드는 무시된다.
interface Animal {
    void sound(); // 추상 메서드

    // default 메서드
    default void breathe() {
        System.out.println("숨을 쉰다");
    }
}

class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println("멍멍");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.sound();   // 멍멍
        dog.breathe(); // 숨을 쉰다 (default 메서드 실행)
    }
}

✅ 인터페이스의 static 메서드

  • 자바 8부터 인터페이스에 static 메서드를 넣을 수 있다.
  • 인터페이스 이름으로 직접 호출해야 하고, 구현 클래스(자식)에서는 상속도, 오버라이딩도 안된다.

👉 즉, 클래스의 static 메서드랑 비슷하지만 인터페이스 소속이라는 차이이다.

interface Animal {
    void sound();

    // static 메서드
    static void info() {
        System.out.println("이건 Animal 인터페이스의 static 메서드야!");
    }
}

class Dog implements Animal {
    @Override
    public void sound() {
        System.out.println("멍멍");
    }
}

public class Main {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.sound(); // 멍멍

        // 인터페이스 static 메서드는 이렇게 호출해야 함
        Animal.info();  // 출력: 이건 Animal 인터페이스의 static 메서드야!
    }
}

✅ 특징 정리

  1. 인터페이스 이름으로만 호출 가능
Animal.info();
  • 객체(dog.info())로는 부르지 못한다.
  1. 상속/재정의 불가
  • 구현 클래스Doginfo() 를 오버라이드할 수 없음.
  • 완전히 인터페이스에 소속된 메서드임.
  1. 유틸리티성 메서드에 자주 사용
  • 예: 데이터 검증, 공통 기능 제공, 상수 관련 로직

📌 마지막 정리

구분선언 방법호출 방법구현 클래스에서 재정의?특징
추상 메서드 (abstract)void run();객체 참조 통해 호출✅ 반드시 구현해야 함규격(계약)만 정의
디폴트 메서드 (default)default void run() { ... }객체 참조 통해 호출✅ 원하면 재정의 가능기본 구현 제공, 필요시 오버라이드
정적 메서드 (static)static void run() { ... }인터페이스명.run();❌ 불가공통 유틸리티 제공, 오버라이드 불가
interface MyInterface {
    // 추상 메서드
    void abstractMethod();

    // default 메서드
    default void defaultMethod() {
        System.out.println("default 메서드 실행");
    }

    // static 메서드
    static void staticMethod() {
        System.out.println("static 메서드 실행");
    }
}

class MyClass implements MyInterface {
    @Override
    public void abstractMethod() {
        System.out.println("추상 메서드 구현");
    }

    // default 메서드 오버라이드 가능
    @Override
    public void defaultMethod() {
        System.out.println("default 메서드 재정의");
    }
}

public class Main {
    public static void main(String[] args) {
        MyClass obj = new MyClass();

        obj.abstractMethod(); // 추상 메서드 구현
        obj.defaultMethod();  // default 메서드 재정의
        MyInterface.staticMethod(); // static 메서드 실행
    }
}
  • 추상 클래스중에, 기본적으로 추상메서드만 가지고 있는 것을 인터페이스로서 특별 취급한다.
  • 인터페이스에 선언된 메서드는 자동적으로 public abstract가 되고, 필드는 public static final이 된다.
  • 복수의 인터페이스를 부모로 두는 다중상속이 가능하다.
  • 인터페이스를 부모로 두는 자식 클래스 정의에 implements를 사용한다.

출처: https://opentutorials.org/module/516/6063

profile
Fill in my own colorful colors🎨

0개의 댓글