JAVA

인터페이스

seungmin576 2024. 12. 26. 11:57

구현 코드가 없는 인터페이스

인터페이스는 클래스 혹은 프로그램이 제공하는 기능을 명시적으로 선언하는 역할을 한다.

인터페이스는 추상 메서드와 상수로만 이루어져 있다.

구현된 코드가 없기 때문에 당연히 인터페이스로 인스턴스를 생성할 수도 없다.

 

인터페이스 만들기

인터페이스를 사용해 간단한 계산기 프로그램을 만든다.

package interfaceex;

public interface Calc {
    double PI = 3.14;
    int ERROR = -999999999;
    //인터페이스에서 선언한 변수는 컴파일 과정에서 상수로 변환됨

    int add(int num1, int num2);
    int subtract(int num1, int num2);
    int times(int num1, int num2);
    int divide(int num1, int num2);
    //인터페이스에서 선언한 메서드는 컴파일 과정에서 추상 메서드로 변환됨
}

계산기를 만들기 위해 선언한 코드이다.

Calc 인터페이스에는 원주율을 뜻하는 PI 변수와 오류가 났을 때 사용할 ERROR 변수, 그리고 사칙 연산을 수행하기 위해 add(), subtract(), times(), divide() 메서드를 선언했다.

인터페이스에 선언한 메서드는 모두 구현 코드가 없는 추상 메서드이다.

이들 메서드는 public abstract 예약어를 명시적으로 쓰지 않아도 컴파일 과정에서 자동으로 추상 메서드로 변환된다.

그리고 인터페이스에 선언한 변수는 모두 컴파일 과정에서 값이 변하지 않는 상수로 자동 변환된다.

public static final 예약어를 쓰지 않아도 무조건 상수로 인식한다.


클래스에서 인터페이스 구현하기

이렇게 선언한 인터페이스를 클래스에서 사용하는 것을 '클래스에서 인터페이스를 구현한다(implements)' 라고 표현한다.

인터페이스에서는 인터페이스에 선언한 기능을 클래스가 구현한다는 의미로 implements 예약어를 사용한다.

 

Calc 인터페이스를 Calculator 클래스에서 구현하는 방법은 다음과 같다

public class Calculator implements Calc {

}

그런데 이렇게 코드를 작성하면 다음과 같은 오류가 표시된다.

위 오류 메시지는 Calc 인터페이스에 포함된 추상 메서드를 구현하거나 Calculator 클래스를 추상 클래스로 만들라는 의미이다.

 

Calc 인터페이스에 선언하 4개의 추상 메서드 중 add()와 subtract() 2개만 구현하여 추상 클래스로 만든 후 이를 상속하는 클래스를 만든다.

package interfaceex;

public abstract class Calculator implements Calc{
    @Override
    public int add(int num1, int num2) {
        return num1 + num2;
    }

    @Override
    public int subtract(int num1, int num2) {
        return num1 - num2;
    }
}

추상 메서드 times()와 divide()를 구현하지 않았으므로 Calculator는 추상 클래스이다.


클래스 완성하고 실행하기

이제 모든 메서드를 구현한 계산기 클래스를 만들어 본다.

Calculator 추상 클래스를 상속받아 CompleteCalc 클래스를 만든다.

 구현하지 않은 times()와 divide() 추상 메서드를 이 클래스에서 구현한다.

package interfaceex;

public class CompleteCalc extends Calculator {
    @Override
    public int times(int num1, int num2) {
        return num1 * num2;
    }

    @Override
    public int divide(int num1, int num2) {
        if (num1 != 2)
            return num1 / num2;
        else
            return Calc.ERROR;
    }

    public void showInfo() {
        System.out.println("Calc 인터페이스를 구현하였다.");
    }

}

숫자를 0으로 나눌 수 없기 때문에 나누는 수 num2가 0이 아닐 때만 나누기 연산을 진행한다.

만약 num2가 0이라면 Calc 인터페이스에서 상수로 선언해 둔 ERROR 메세지를 반환한다.

 

  • 테스트프로그램
package interfaceex;

public class CalculatorTest {
    public static void main(String[] args) {
        int num1 = 10;
        int num2 = 5;

        CompleteCalc calc = new CompleteCalc();
        System.out.println(calc.add(num1, num2));
        System.out.println(calc.subtract(num1, num2));
        System.out.println(calc.times(num1, num2));
        System.out.println(calc.divide(num1, num2));
        calc.showInfo();
    }
}

10과 5를 더하기 빼기 곱하기 나누기기 연산을 하고 결과 값 출력.

구체적인 클래스인 CompleteCalc 클래스만 인스턴스를 생성할 수 있다.

Calculator 클래스는 추상 클래스이므로 인스턴스를 생성할 수 없고, Calc 인터페이스는 추상 메서드만으로 선언되었기 때문에 인스턴스를 생성할 수 없다.


인터페이스 구현과 형 변환

Calculator 클래스는 인터페이스에서 선언한 추상 메서드 중 일부 메서드만 구현했으므로 추상 클래스이다.

그리고 이를 상속받은 CompleteCalc 클래스는 Calculator 클래스에서 구현하지 않은 나머지 추상 메서드를 모두 구현하고 showInfo() 메서드를 추가로 구현했다.

이러한 관계에서 하위 클래스의 형 변환은 어떻게 이루어지는지 살펴본다.

 

상속 관계에서 하위 클래스는 상위 클래스 자료형으로 묵시적 형 변환할 수 있다고 했다.

인터페이스도 마찬가지이다.CompleteCalc 클래스는 상위 클래스인 Calculator형이면서, Calc 인터페이스를 구현하였으므로 Calc형이기도 하다.

따라서 별다른 조치 없이 다음처럼 Calc형으로 선언한 변수에 대입할 수 있다.

Calc calc = new CompleteCalc();

 

calc 변수를 Calc형 변수인 newCalc에 대입하고 Ctrl + Spacebar를 눌러 newCalc 변수가 사용할 수 있는 메서드를 살펴보자.

newCalc 변수가 사용할 수 있는 메서드 목록에 Calc에서 선언한 추상 메서드는 있지만, CompleteCalc 클래스에서 추가로 구현한 showInfo() 메서드는 없다.

즉 Calc형으로 선언한 변수에서 사용할 수 있는 메서드는 Calc 인터페이스에 선언한 메서드 뿐이다.

정리하면 인터페이스를 구현한 클래스가 있을 때 그 클래스는 해당 인터페이스형으로 묵시적 형 변환이 이루어지며, 형 변환되었을 때 사용할 수 있는 메서드는 인터페이스에서 선언한 메서드뿐이다.

 

  • 각 자료형에서 사용할 수 있는 메서드 범위 그림