Java & Kotlin

[Java 객체지향] 인터페이스

Sue 2022. 2. 1. 14:33

인터페이스

  • 모든 메서드의 구현 코드가 없는 추상 자료형
  • 모든 메서드가 추상 메서드로 선언된다. (public abstract)
  • 모든 변수는 상수로 선언된다. (public static final) - 인터페이스는 구현코드가 없으므로 멤버 변수를 가질 수 없음
  • 따로 키워드를 넣어주지 않아도 자동으로 추상 메서드 또는 상수로 컴파일 된다.
  • 자바에서 모호성을 피하기 위해 단일 상속만 가능하지만, 인터페이스는 구현 코드가 없기 때문에 여러개를 구현하는데 모호성이 발생하지 않는다.

 

구현과 상속

  • 인터페이스를 다른 클래스에서 구현하는 것은 상속과는 다른 의미이다.
  • 상속은 이미 구현된 코드를 재사용하는 것이다.
  • 인터페이스는 구현된 코드가 없다.
  • 다른 클래스에서 인터페이스에 선언된 메서드를 재정의하여 사용하는 것을 인터페이스를 구현한다고 한다.
  • 인터페이스의 일부만 구현하면 추상 클래스, 모든 메서드를 구현하면 인스턴스화 될 수 있는 클래스이다.

 

예제 코드

클래스 다이어그램
  • 점선은 인터페이스의 구현(implements)을 나타냄

 

Calc.java
package ch11;

public interface Calc {
	
	double PI = 3.14;	// public static final
	int ERROR = -999999999;
	
	int add(int num1, int num2);	// public abstract
	int substract(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);
}

 

Calculator.java
package ch11;

public abstract class Calculator implements Calc{	// interface의 일부 메서드만 구현

	@Override
	public int add(int num1, int num2) {
		return num1 + num2;
	}

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

}

 

CompleteCalc.java
  • 모든 메서드를 구현하여 CompleteCalc 클래스는 인스턴스화 될 수 있다.
package ch11;

public class CompleteCalc extends Calculator {	// interface의 나머지 메서드 모두 구현

	@Override
	public int times(int num1, int num2) {
		return num1 * num2;
	}

	@Override
	public int divide(int num1, int num2) {
		if (num2 == 0) {
			return ERROR;
		}
		else {
			return num1/num2;
		}
	}
	
	public void showInfo() {
		System.out.println("모두 구현했습니다.");
	}

}

 

CalculatorTest.java
  • 인터페이스를 구현한 CompleteCalc 클래스는 인터페이스 형 변수로 형변환 될 수 있다. 
  • 형변환된 경우 인터페이스에 선언된 메서드만 사용 가능하다.
  • 클래스는 여러개의 인터페이스를 implement 할 수 있다. (여러 개의 타입을 내포할 수 있음)
package ch11;

public class CalculatorTest {

	public static void main(String[] args) {
		
		int num1 = 10;
		int num2 = 2;
		
		Calc calc = new CompleteCalc();	// 인터페이스 형 변수로 형변환
		System.out.println(calc.add(num1,num2));
		System.out.println(calc.substract(num1, num2));
		System.out.println(calc.divide(num1, num2));
		System.out.println(calc.times(num1, num2));
		
	}

}

 

수행 결과
12
8
5
20

 

인터페이스 사용 이유

  • 사람과 TV를 연결해주는 리모컨을 생각해보면, 사람은 리모컨의 동작 원리는 몰라도 버튼을 눌러 작동시킬 수 있다.
  • 인터페이스는 구현하는 클래스나 프로그램이 제공하는 기능을 명시적으로 선언해놓은 것이다.
  • 프로그램을 제공하는 모듈인 서버 코드와 사용하는 쪽의 클라이언트 코드가 있을 때 클라이언트는 서버가 어떻게 구현되어 있는지 모르고 쓰는 경우가 많다.
  • 이럴 때 클라이언트는 인터페이스의 메서드를 보고 사용한다.
  • 인터페이스에는 어떤 메서드를 호출해서 어떤 매개변수를 주면 어떤 반환값을 주는지 명세되어 있다.
  • 어떤 객체가 하나의 인터페이스 타입이라는 것은 그 인터페이스가 제공하는 모든 메서드를 구현했다는 의미이다.
  • 인터페이스를 구현한 다양한 객체를 사용하지만 메서드를 사용하는 방식은 동일하다. (다형성)
  • 여러 모듈을 바꿔가면서 호출해서 쓸 때, 호출 하는 쪽에서는 코드가 변경될 필요가 없다. 어떤 모듈을 쓰던 사용하는 방식은 동일하기 때문

 

예시) JDBC 인터페이스

  • 자바와 DB를 연결할 때 자바에 정의되어 있는 connection 객체를 이용한다.
  • 이때 Connection은 인터페이스이며 이를 구현하는 것은 서버쪽(mySQL, Oracle, MS-SQL ...)이다.
  • 서버쪽은 라이브러리인 jar 파일을 생성해 제공한다.
  • 클라이언트쪽은 jar 파일이 어떻게 구현되어 있는지 알 필요가 없다.