자바 리마인드#12 인터페이스
2023/02/07
- 학습내용
1. 인터페이스(interface)
인터페이스는 클래스 혹은 프로그램이 제공하는 기능을 명시적으로 선언하는 역할을 한다.
인터페이스는 추상 메서드와 상수로만 이루어져 있다.
구현된 코드가 없기 때문에 당연히 인터페이스로 인스턴스를 생성할 수도 없다.
1) 인터페이스 ex)
//Calc 인터페이스
public interface Calc {
double PI = 3.14; //인터페이스에서 선언한 변수는 컴파일과정에서 상수로 변환됨
int ERROR = -999999999;
int add(int num1, int num2);//인터페이스에서 선언한 메서드는 컴파일 과정에서 추상 메서드로 변환됨
int substract(int num1, int num2);
int times(int num1, int num2);
int divide(int num1, int num2);
}
Calc 인터페이스는 계산기를 만들기 위해 선언한 코드다.
원주율을 뜻하는 PI변수와 ERROR 변수, 사칙 연산을 수행하기 위해 add, substract, times, divide 메서드를 선언했다.
인터페이스에 선언한 메서드는 모두 구현 코드가 없는 추상 메서드다.
이 메서드들은 public abstract 예약어를 명시하지 않아도 컴파일 과정에서 자동으로 추상 메서드로 변환된다.
또한 인터페이스의 변수들도 public static final 예약어를 쓰지 않아도 컴파일 과정에서 상수로 자동 변환된다.
2) 클래스에서 인터페이스 구현(implements)
선언한 인터페이스를 클래스가 사용하는 것을 '클래스에서 인터페이스를 구현한다(implements)' 라고 표현한다.
인터페이스에서는 인터페이스에 선언한 기능을 클래스가 구현한다는 의미로 implements 예약어를 사용한다.
//Calc 클래스를 구현한 Calculator 추상 클래스
public abstract class Calculator implements Calc { //추상 클래스
@Override
public int add(int num1, int num2) {
return num1 + num2;
}
@Override
public int substract(int num1, int num2) {
return num1 - num2;
}
}
//계산서 클래스 만들기
public class CompleteCale extends Calculator {
@Override
public int times(int num1, int num2) {
return num1 * num2;
}
@Override
public int divide(int num1, int num2) {
if(num2 != 0)
return num1 * num2;
else
return Calc.ERROR; //num2가 0, 나누는 수가 0인 경우에 대해 오류 반환
}
public void showInfo() {
System.out.println("Calc 인터페이스를 구현하였습니다");
}
}
Calculator 추상 클래스를 상속받아 CompleteCale 클래스를 만들었다.
Calculator 클래스에서 구현하지 않은 time()와 divide() 추상 메서드를 CompleteCale 클래스에서 구현한다.
이러면 이제 Calc 인터페이스의 모든 메서드를 구현한 계산기 클래스가 된다.
3) 인터페이스 구현과 형 변환
상속 관계에서 하위 클래스는 상위 클래스 자료형으로 묵시적 형 변환할 수 있다.
인터페이스도 마찬가지다.
CompleteCalc 클래스는 Calculator형이면서, Calc형이기도 하다.
Calc calc = new CompletCalc();
별다른 조치 없이 Calc형으로 선언한 변수에 대입할 수 있다.
형 변환시 사용할 수 있는 메서드는 인터페이스에 선언된 메서드만 사용할 수 있다.
2. 인터페이스와 다형성
1) 인터페이스의 역할
인터페이스는 클라이언트 프로그램에 어떤 메서드를 제공하는지 미리 알려주는 명세 또는 약속의 역할을 한다.
인터페이스는 객체의 교환성(또는 다형성)을 높여준다.
인터페이스 변수에 인터페이스가 구현된 서로 다른 구현 객체를 할당해서 사용이 가능하다.
구현 객체를 직접 몰라도 인터페이스 메서드만 알아도 객체 호출이 가능하게 한다.
객체가 인터페이스를 사용하면, 인터페이스 메서드를 반드시 구현해야 하는 제약이 있다.
"interface를 이용하여, 개발 코드를 직접 수정하지 않고도, 사용하고 있는 객체만 변경할 수 있도록 하기 위함이다."
2) 인터페이스와 다형성
인터페이스를 사용하면 다형성을 구현하여 확장성 있는 프로그램을 만들 수 있다.
클라이언트 프로그램을 많이 수정하지 않고 기능을 추가하거나 다른 기능을 사용할 수 있다.
3. 인터페이스 요소
1) 인터페이스 상수
인터페이스는 추상 메서드로 이루어지므로 인스턴스를 생성할 수 없으며 멤버 변수도 사용할 수 없다.
//Calc 인터페이스
public interface Calc {
double PI = 3.14; //인터페이스에서 선언한 변수는 컴파일과정에서 상수로 변환됨
int ERROR = -999999999;
int add(int num1, int num2);//인터페이스에서 선언한 메서드는 컴파일 과정에서 추상 메서드로 변환됨
int substract(int num1, int num2);
int times(int num1, int num2);
int divide(int num1, int num2);
}
그런데 인터페이스에 위 코드와 같이 변수를 선언해도 오류가 발생하지 않는다.
이유는 인터페이스에 선언한 변수를 컴파일하면 상수로 자동으로 변환되기 떄문이다.
※ 자동으로 public static final double PI = 3.14; , public static final int ERROR = -99999999; 로 변환되어 상수로 취급된다.
2) 디폴트 메서드와 정적 메서드
JAVA8부터는 디폴트 메서드와 정적 메서드 기능이 제공된다.
디폴트 메서드 : 인터페이스에서 구현 코드까지 작성한 메서드이다.
디폴트 메서드는 말 그대로 기본으로 제공되는 메서드이다.
디폴트 메서드는 인터페이스에서 구현하지만,
이후 인터페이스를 구현한 클래스가 생성되면 그 클래스에서 사용할 기본 기능이다.
디폴트 메서드를 선언할 때는 default 예약어를 사용한다.
※디폴트 메서드는 인터페이스를 구현한 클래스에 따로 코드를 구현할 필요없이 호출하면 된다.
정적 메서드 : 인스턴스 생성과 상관없이 사용할 수 있는 메서드이다.
정적 메서드는 static 예약어를 사용하여 선언하며 클래스 생성과 무관하게 사용할 수 있다.
정적 메서드를 사용할 때는 인터페이스 이름으로 직접 참조하여 사용한다.
3) private 메서드
private 메서드를 사용하면 인터페이스를 구현한 클래스에서 사용하거나 재정의 할 수 없다.
인터페이스 내부에서만 기능을 제공하기 위해 구현하는 메서드이다.
(하위 클래스에서 오버라이딩 불가능, 내부에서만 사용)
private 혹은 private static으로 선언. (private static은 정적 메서드에서 사용 가능하다.)