[JAVA] 인터페이스

dejeong·2024년 9월 14일
1

JAVA

목록 보기
13/24
post-thumbnail

인터페이스 (Interface)

인터페이스는 객체의 기능을 정의한 일종의 껍데기로, 추상 메서드만 포함하며 실제 구현 내용은 포함되지 않는다. 인터페이스에 선언된 추상 메서드는 이를 구현한 클래스에서 반드시 구현해야 한다. 이 규칙은 추상 클래스와 동일하다.

주요 특징

  1. 타입 역할: 인터페이스는 해당 인터페이스를 구현한 클래스의 타입이 될 수 있다. 즉, 다형성을 지원하며 구현체의 타입을 유연하게 선언할 수 있다.
  2. 다중 상속 가능: 한 클래스가 여러 개의 인터페이스를 구현할 수 있어 다중 상속이 가능하다.
  3. 필드와 메서드 제한: 인터페이스는 static final 상수만 필드로 가질 수 있으며, 추상 메서드와 default 메서드만 포함할 수 있다. 일반 메서드는 포함할 수 없다.

인터페이스의 다형성

인터페이스를 구현한 여러 클래스가 동일한 인터페이스 메서드를 구현하되, 각기 다른 방식으로 동작하도록 할 수 있다. 이는 코드의 유연성을 높인다.

package chap08.payment;

public interface Payment {
    void processPayment(double amount);
}

다양한 클래스에서 Payment 인터페이스를 구현할 수 있다.

public class CreditCard implements Payment {
    private String cardNumber;

    public CreditCard(String cardNumber){
        this.cardNumber = cardNumber;
    }

    @Override
    public void processPayment(double amount) {
        System.out.println("Processing credit card payment of $" + amount + " using card number: " + cardNumber);
    }
}

public class Paypal implements Payment {
    private String email;

    public Paypal(String email) {
        this.email = email;
    }

    @Override
    public void processPayment(double amount) {
        System.out.println("Processing PayPal payment of $" + amount + " using email: " + email);
    }
}

사용 예시

public class PaymentProcess {
    public static void main(String[] args) {
        Payment creditCard = new CreditCard("12345-67890");
        creditCard.processPayment(67000);

        Payment paypal = new Paypal("email@aws.com");
        paypal.processPayment(67000);
    }
}

위 예시에서 Payment 인터페이스를 사용해 두 가지 결제 방식(신용카드, 페이팔)을 유연하게 처리할 수 있다. 이는 다형성의 대표적인 예다.

추가 내용: Default 메서드와 Static 메서드

Java 8 이후 인터페이스에 default 메서드와 static 메서드를 포함할 수 있게 되었다.

  • default 메서드: 인터페이스에서 기본 구현을 제공할 수 있어, 인터페이스가 진화하더라도 기존 구현체가 해당 메서드를 반드시 오버라이드할 필요는 없다.
  • static 메서드: 인터페이스 자체에서 호출할 수 있는 메서드로, 구현체와는 무관하게 동작한다.
public interface Vehicle {
    default void start() {
        System.out.println("Vehicle is starting.");
    }

    static void stop() {
        System.out.println("Vehicle has stopped.");
    }
}

추상 클래스(abstract class)와 인터페이스(interface) 비교

구분추상 클래스 (abstract class)인터페이스 (interface)
사용 키워드abstractinterface
사용 가능 변수제한 없음 (일반 필드, static final 모두 가능)static final (상수만 가능)
사용 가능 접근 제어자제한 없음 (public, private, protected, default)public (모든 메서드는 기본적으로 public)
사용 가능 메서드제한 없음 (추상 메서드, 일반 메서드 모두 가능)abstract method, default method, static method, private method
상속 키워드extendsimplements
다중 상속 가능 여부불가능 (단일 상속만 가능)가능 (클래스에 다중 구현, 인터페이스끼리 다중 상속 가능)
구현 강제성일부 메서드는 구현하지 않아도 됨모든 추상 메서드는 구현 클래스에서 필수
유연성특정 클래스 계층 구조에서만 사용 가능여러 클래스에서 동일 기능을 제공 가능

| 공통점 | 1. 추상 메서드를 가질 수 있음
2. 인스턴스화 불가능 (new 생성자 사용 불가)
3. 추상 클래스나 인터페이스를 구현한 인스턴스를 사용해야 함
4. 추상 메서드를 상속받은 클래스는 반드시 구현해야 함 |
| --- | --- |

인터페이스가 필요한 이유

새로운 기능을 추가할 때, 추상 클래스와 인터페이스의 차이는 크게 유연성다중 상속 여부에서 차이가 난다.

  • 추상 클래스는 상속 관계에서 사용된다. 예를 들어, abstract class Payment를 사용한다면, BitCoin은 오직 Payment만 상속받을 수 있으며, 다른 클래스를 상속받는 것이 불가능하다.
    abstract class Payment {}
    public class BitCoin extends Payment {}
    
    abstract class Virtual {} // 다중 상속 불가 (X)
  • 반면에 인터페이스를 사용하면, 클래스가 여러 인터페이스를 구현할 수 있으므로, 다중 구현이 가능하다.
    interface Payment {}
    interface Virtual {}
    public class BitCoin implements Payment, Virtual {} // 다중 구현 가능 (O)

차이점

  • 추상 클래스Is a 관계, 즉 상속관계를 표현하는 데 사용된다.예: C is A -> CA에 포함된다.
  • 인터페이스Has a 관계, 즉 특정 기능이나 능력을 표현하는 데 사용된다.예: C has a I -> CI의 기능을 갖는다.

따라서 인터페이스의 유연한 확장성이 큰 장점이다. 여러 클래스가 같은 기능을 공통으로 사용할 수 있게 해주는 것이 인터페이스의 주요 목적이다.

예시: 동물 먹이 주기

기존의 Zookeeper 클래스에서는 각각의 동물마다 별도의 메서드를 만들었지만, 인터페이스를 사용하면 하나의 메서드로 여러 객체를 받을 수 있어 중복 코드를 줄일 수 있다.

public class Zookeeper {
    void feed(Lion lion){
        System.out.println("feed fish");
    }

    void feed(Tiger tiger){
        System.out.println("feed meat");
    }
}

인터페이스를 적용하여 아래처럼 타입을 통일할 수 있다.

public class Zookeeper {
    void feed(Predator predator){
        System.out.println("feed " + predator.getFood());
    }
}
  • Predator 인터페이스를 사용하면 Lion, Tiger와 같은 동물들이 각각 다른 음식을 받을 수 있다.
public interface Predator {
    String getFood();
}

public class Lion implements Predator {
    @Override
    public String getFood() {
        return "fish";
    }
}

public class Tiger implements Predator {
    @Override
    public String getFood() {
        return "meat";
    }
}

결과: Zookeeper 클래스는 어떤 동물이 들어오더라도 동일한 방식으로 처리할 수 있게 된다.

인터페이스 타입 선언

인터페이스로 구현 객체를 사용할 때, 인터페이스 타입으로 변수를 선언하고, 구현 객체를 대입할 수 있다.

Predator predator = new Lion();

이렇게 하면 Lion이든 Tiger이든 하나의 타입으로 처리할 수 있어 코드가 유연해지고, 확장 가능해진다.

인터페이스의 다형성

인터페이스의 다형성하나의 인터페이스 타입여러 객체를 대입할 수 있게 해준다. 이렇게 하면 객체의 타입에 따라 다른 동작을 할 수 있다.

디폴트 메서드 (Java 8 이후)

  • 디폴트 메서드는 인터페이스 안에서 기본적인 구현을 제공한다. 인터페이스가 변경되더라도 기존 구현체에 영향을 주지 않기 위해 추가된 기능이다.
public interface Predator {
    default void hunt() {
        System.out.println("Default hunting method");
    }
}

인터페이스에서 사용할 수 없는 것

인터페이스에서는 인스턴스 변수를 사용할 수 없고, 생성자도 가질 수 없다. 하지만 정적 메서드, 디폴트 메서드, private 메서드는 사용할 수 있다.

profile
룰루

0개의 댓글