[Java] 인터페이스(interface)

·2024년 7월 6일
0

Java

목록 보기
7/9
post-thumbnail

인터페이스의 역할

자바에서 인터페이스는 객체의 사용 방법을 정의한 타입이다.

개발 코드와 객체가 서로 통신하는 접점 역할을 한다. 개발 코드가 인터페이스의 메소드를 호출하면 인터페이스는 객체의 메소드를 호출시킨다. 때문에 개발 코드는 객체의 내부 구조를 알 필요가 없고 인터페이스의 메소드만 알고 있으면 된다.

그럼 개발 코드가 직접 객체의 메소드를 호출하지 않고, 왜 중간에 인터페이스를 두는 것인가?

그 이유는 개발 코드를 수정하지 않고, 사용하는 객체를 변경할 수 있도록 하기 위해서다.

무슨 소리인지 이해가 잘 안된다면, 다음 예시를 보자.

  1. interface Shape
public interface Shape {
    void draw();
}
  1. interface Shape의 구현체
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("원 그리기");
    }
}

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("직사각형 그리기");
    }
}
  1. Shape를 그리는 Canvas 클래스
public class Canvas {
    private Shape shape;

    public Canvas(Shape shape) {
        this.shape = shape;
    }

    public void drawShape() {
        shape.draw();
    }
}
  1. 사용
public class Main {
    public static void main(String[] args) {
        // 원을 그리는 경우
        Shape circle = new Circle();
        Canvas canvas = new Canvas(circle);
        canvas.drawShape();  // 원그리기

        // 직사각형으로 변경하는 경우
        Shape rectangle = new Rectangle();
        canvas = new Canvas(rectangle);
        canvas.drawShape();  // 직사각형 그리기
    }
}

3.코드에 있는 Canvas 클래스를 살펴보자. 이 클래스는 Shape를 변수로 갖고, drawShape()라는 메소드에서는 shape.draw() 함수를 호출한다.

4.코드에 있는 메인문을 살펴보면, Circle 객체를 만들어 Canvas에 넣으면 원을 그리고, Rectangle 객체를 만들어 Canvas에 넣으면 직사각형을 그린다. 즉, Canvas 클래스는 어떤 모양 객체가 주어지든 상관없이 모양을 그릴 수 있게 된다. 직접 객체의 메소드를 사용하지 않고 인터페이스를 사용했기 때문에 코드의 수정이 없어도 정상적으로 동작한다.

인터페이스 선언

자바에서 인터페이스 선언은 class 키워드 대신에 interface를 붙여주면 된다. 인터페이스는 상수와 메소드만을 구성 멤버로 가진다. 객체로 생성할 수 없으므로 생성자를 가질 수 없다.

인터페이스에서 상수 필드를 선언할 때는 반드시 초기값을 대입해야 하며, public static final로 생성해야 한다. 생략하더라도 컴파일 과정에서 자동으로 붙게된다.

인터페이스에서 호출된 메소드는 최종적으로 객체에서 실행되게 되므로, 인터페이스의 메소드는 실행 블록이 없는 추상 메소드로 선언한다. 추상 메소드는 리턴 타입, 메소드명, 매개 변수만 기술된다.

// ex
public interface RemoteControl {
	public void turnOn();
	public void setVolume(int volume)
}

구현 클래스

객체는 실체 메소드를 갖는데 이를 인터페이스의 구현 객체라고 하고, 구현 객체를 생성하는 클래스를 구현 클래스라고 한다. 클래스 선언부에 implements를 붙여준다.

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("원 그리기");
    }
}

아래와 같이 다중 인터페이스도 구현할 수 있다.

public interface Shape {
    void draw();
}

public interface Colorable {
    void color();
}
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("원 그리기");
    }
    
    @Override
    public void color() {
        System.out.println("원 색칠하기");
    }
}

구현할 때 주의할 점은 인터페이스의 모든 메소드는 기본적으로 public 접근 제한을 갖기 때문에 public 보다 낮은 접근 제한으로 작성할 수 없다. 또 인터페이스에 있는 모든 메소드를 구현하지 않으면 추상 클래스가 되어야 하므로 주의해야 한다. 해당 클래스에 abstract 키워드를 붙여야 하고 추상 클래스를 상속받는 구체적인 클래스가 나머지 메소드를 구현해야 한다.

인터페이스 사용

인터페이스로 구현 객체를 사용하려면 인터페이스 변수를 선언하고 구현 객체를 대입해야 한다. 인터페이스 변수는 참조 타입이기 때문에 구현 객체가 대입될 경우 구현 객체의 번지를 저장한다.

인터페이스 변수;
변수 = 구현객체;

or

인터페이스 변수 = 구현객체;

인터페이스와 다형성

다형성은 하나의 타입에 대입되는 객체에 따라서 실행 결과가 다양한 형태로 나오는 성질을 말한다. 인터페이스 타입에 어떤 객체를 대입하느냐에 따라 실행 결과가 달라진다.

프로그램을 개발할 때 인터페이스를 사용해서 메소드를 호출하도록 코딩을 했다면, 구현 객체를 교체하는 것은 매우 손쉽고 빠르게 할 수 있다. 프로그램 소스 코드는 변함이 없는데, 구현 객체를 교체함으로써 프로그램의 실행 결과가 다양해진다. 이것이 인터페이스의 다형성이다.

인터페이스와 추상 클래스의 차이점?

문득 인터페이스와 추상 클래스의 차이점은 뭔지에 대해 궁금해져, 표로 정리해보았다.

인터페이스 (Interface)추상 클래스 (Abstract Class)
목적클래스가 구현해야 하는 메소드 집합을 정의공통 기능을 공유하고 코드 중복을 줄이기 위함
다중 상속가능불가능 (단일 상속만 가능)
메소드 구현기본적으로 추상 메소드추상 메소드와 구체적 메소드 모두 포함 가능
변수public, static, final (상수)인스턴스 변수 가질 수 있음
접근 제어자메소드는 암묵적으로 public메소드와 변수는 다양한 접근 제어자 사용 가능
인스턴스 생성불가능불가능 (추상 클래스 자체로는 인스턴스 생성 불가)
상속 키워드implementsextends
상속 관계다중 인터페이스 구현 가능하나의 추상 클래스만 상속 가능

인터페이스와 상속의 차이점?

그렇다면 인터페이스와 상속의 차이는 뭔지에 대해서도 생각해봤다.

  • 상속
    • 기존 클래스의 기능을 재사용하고 확장하는 데 사용
    • 단일 상속만 가능
    • 부모 클래스의 메소드와 변수를 상속받아 재사용하고 확장할 수 있음
    • is-a 관계
  • 인터페이스:
    • 클래스가 구현해야 하는 메소드 집합을 정의
    • 여러 인터페이스를 구현할 수 있음
    • 인터페이스의 메소드는 기본적으로 추상 메소드

상속은 같은 종류의 하위 클래스를 만드는 기술이고, 인터페이스는 사용 방법이 동일한 클래스를 만드는 기술이라는 개념적 차이는 있지만 둘 다 다형성을 구현하는 기술이다.

정적 메소드(Static Method)와 디폴트 메소드(Default Method)

Java 8부터 인터페이스에 도입되었다고 한다.

  1. 정적 메소드

    : 인터페이스 자체에서 호출할 수 있는 메소드. 객체 인스턴스를 생성하지 않고 호출할 수 있다.

  2. 디폴트 메소드

    : 인터페이스에서 구현을 제공하는 메소드. 인터페이스를 구현하는 클래스에서 오버라이드 하지 않아도 된다.

    기존 인터페이스에 새로운 메소드를 추가하되, 해당 인터페이스를 구현하는 기존 클래스가 영향을 받지 않도록 할 때 유용하다!

이 포스팅은 신용권, ⌜이것이 자바다-신용권의 Java 프로그래밍 정복⌟, 한빛미디어(주) 책을 참고했습니다.

profile
개발블로그👩🏻‍💻

0개의 댓글