개발/Java

[Java] 인터페이스(Interface)란?

nova_dev 2020. 7. 14. 09:04
반응형

인터페이스(interface)란? 
인터페이스(Interface)

인터페이스가 무엇인지 알아보고 인터페이스의 요소와 인터페이스를 활용한 다형성 구현에 대해 알아보자.

 인터페이스의 역할

인터페이스는 클라이언트 프로그램에 어떤 메서드를 제공하는지 알려주는 명세(specification) 또는 약속이다.

한 객체가 어떤 인터페이스의 타입이라 함은 그 인터페이스의 메서드를 구현했다는 의미이며 클라이언트 프로그램은 실제 구현내용을 몰라도 인터페이스의 정의만 알면 그 객체를 사용할 수 있다.

인터페이스를 구현해 놓은 다양한 객체를 사용하는 것을 다형성이라고 하는데 예를 들면, JDBC를 구현한 오라클, MySQL라이브러리 등에서 어떤 인터페이스에 대한 구현을 각각 했을 때, 사용자는 인터페이스의 정의만을 보고 JDBC나 MySQL의 실제 구현은 모르는 상태로 원하는 DB를 jar파일로 import 하여 어떤 메서드를 호출하여 사용할지 정할 수 있다.

예를 들면 아래와 같은 인터페이스를 볼 수 있다.

Connection Interface

 실습 해보기 (인터페이스의 기본 구조)

고객센터에는 전화 상담을 하는 상담원들이 있다. 일단 고객 센터로 전화가 오면 대기열에 저장되며, 상담원이 지정되기 전까지 대기 상태가 된다. 각 전화가 상담원에게 배분되는 정책은 다음과 같이 여러 방식으로 구현될 수 있다.

- 상담원 순서대로 배분하기 (Round Robin)
- 대기가 짧은 상담원 먼저 배분하기 (Least Queue)
- 우선순위가 높은(숙련도 높은) 상담원에게 먼저 배분하기 (Priority)

위와 같이 다양한 정책이 사용되는 경우 interface를 정의하고 다양한 정책을 구현하여 실행한다.

package chapter9.scheduler;

public interface Scheduler {
	public void getNextCall();
	public void sendCallToAgent();
}
package chapter9.scheduler;

public class RoundRobin implements Scheduler{

	@Override
	public void getNextCall() {
		System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
	}

	@Override
	public void sendCallToAgent() {
		System.out.println("다른 순서의 상담원에게 배분합니다.");
	}

}
package chapter9.scheduler;

public class LeastJob implements Scheduler{

	@Override
	public void getNextCall() {
		System.out.println("상담 전화를 순서대로 대기열에서 가져옵니다.");
	}

	@Override
	public void sendCallToAgent() {
		System.out.println("현재 상담업무가 없거나 상담대기가 가장 적은 상담원에게 할당합니다.");
	}

}
package chapter9.scheduler;

public class PriorityAllocation implements Scheduler {

	@Override
	public void getNextCall() {
		System.out.println("고객등급이 높은 고객의 call을 먼저 가져옵니다.");
	}

	@Override
	public void sendCallToAgent() {
		System.out.println("업무 숙련도가 높은 상담원에게 먼저 배분합니다.");
	}
	
}


실행 결과

 인터페이스의 요소

1. 추상메서드: 인터페이스에서 선언되는 모든 메서드
2. 상수: 인터페이스에서 선언되는 모든 변수
3. 디폴트 메서드: 기본 구현을 가지는 메서드. 구현하는 클래스에서는 재정의할 수 있음 (java8)
4. 정적 메서드: 인스턴스 생성과 상관 없이 인터페이스 타입으로 호출하는 메서드(java8)
5. private 메서드: 인터페이스 내에서 사용하기 위해 구현한 메서드

public interface Calc {
	double PI = 3.14; // 이테릭체로 public static final이 자동으로 추가됨.
	int ERROR = -99999999;
	
	int add(int num1, int num2);
	int substract(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);
}

인터페이스에 포함된 모든 변수들은 상수로 정의된다. 즉, 사용자가 PI나 ERROR와 같은 변수를 생성할 경우 이 값은 시스템에서 자동으로 public static final 키워드를 붙여 상수로 변환시킨다. 

기본적으로 정의한 메서드(add, substract, times, divide 같은)는 자동으로 추상메서드로 변환된다. 즉, 시스템에서 자동으로 메서드에 abstract 키워드를 붙인다.

추가로 디폴트 메서드와 정적 메서드, private 메서드는 java 최근 버전에 추가되었으며 중복 구현을 막기 위해 기본적으로 제공되는 메서드이다.

 타입 상속과 형변환

인터페이스를 구현한 클래스는 인터페이스 타입으로 변수를 선언하여 인스턴스를 생성할 수 있다.

multiple inheritance가 가능한 cpp 에서 있을 수 있는 다이아몬드 문제 (Diamond Problem)과 같은 것을 해결하기 위해Interface가 아닌 일반 Class를 상속 받을 경우 Java에서는 Single Inheritance만 가능하다.

이때 인터페이스간의 상속도 가능하다. 인터페이스의 경우에는 구현이 없으므로 extends 뒤에 여러 인터페이스를 상속 받을 수 있는데 이를 타입 상속(type inheritance)이라고도 한다. 디폴트 메서드의 이름이 중복되는 경우에는 재정의(overriding)하여 사용한다.

 실습 해보기 (Default Method)

package chapter9.interfaceex;

public interface Calc {
	double PI = 3.14; // 이테릭체로 public static final이 자동으로 추가됨.
	int ERROR = -99999999;
	
	int add(int num1, int num2);
	int substract(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);

	default void description() {
		System.out.println("점수 계산기를 구현합니다.");
	}
}
package chapter9.interfaceex;

public class CalcTest {

	public static void main(String[] args) {
		Calc calc = new CompleteCalc(); 
		int num1 = 10;
		int num2 = 2;
		
		System.out.println(calc.add(num1, num2));
		System.out.println(calc.substract(num1, num2));
		System.out.println(calc.times(num1, num2));
		System.out.println(calc.divide(num1, num2));

		calc.description();
	}

}

오버라이드 메서드 이클립스에서 편하게 추가하기

 실습 해보기 (Static Method)

package chapter9.interfaceex;

public interface Calc {
	double PI = 3.14; // 이테릭체로 public static final이 자동으로 추가됨.
	int ERROR = -99999999;
	
	int add(int num1, int num2);
	int substract(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);

	default void description() {
		System.out.println("점수 계산기를 구현합니다.");
	}
	
	/*
	 * array의 합을 계산해서 반환하는 메서드
	 * 추상메서드로만 제공이 되면 각각 구현을 해야 하고 default로 제공되면 인스턴스를 생성해서 만들어야 함.
	 * 따라서 인스턴스를 생성하지 않고 유틸처럼 사용할 수 있는 기능은 인터페이스에서도 static으로 제공할 수 있음.
	 */
	static int total(int[] arr){
		int total = 0;
		
		for(int i: arr) {
			total += i;
		}
		return total;
	}
	
}
package chapter9.interfaceex;

public class CalcTest {

	public static void main(String[] args) {
		Calc calc = new CompleteCalc(); 
		int num1 = 10;
		int num2 = 2;
		
		System.out.println(calc.add(num1, num2));
		System.out.println(calc.substract(num1, num2));
		System.out.println(calc.times(num1, num2));
		System.out.println(calc.divide(num1, num2));

		/*
		 *  인터페이스를 구현한 클래스라고 하더라도
		 *  인터페이스에 포함되지 않은  추가된 메서드는 사용할 수 없다. 
		 */
		//calc.showInfo();
		calc.description();
		int[] arr = {1,2,3,4,5};
		System.out.println("배열의 합은 "+Calc.total(arr)+"입니다.");
	}

}

 실습 해보기 (Private Method)

package chapter9.interfaceex;

public interface Calc {
	double PI = 3.14; // 이테릭체로 public static final이 자동으로 추가됨.
	int ERROR = -99999999;
	
	int add(int num1, int num2);
	int substract(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);

	default void description() {
		System.out.println("점수 계산기를 구현합니다.");
		myMethod();
	}
	
	/*
	 * array의 합을 계산해서 반환하는 메서드
	 * 추상메서드로만 제공이 되면 각각 구현을 해야 하고 default로 제공되면 인스턴스를 생성해서 만들어야 함.
	 * 따라서 인스턴스를 생성하지 않고 유틸처럼 사용할 수 있는 기능은 인터페이스에서도 static으로 제공할 수 있음.
	 */
	static int total(int[] arr){
		int total = 0;
		
		for(int i: arr) {
			total += i;
		}
		mystaticMethod();
		return total;
	}
	
	/*
	 * private 메서드는 java9부터 제공한다.
	 * 사용할 경우 JRE 버전을 확인한다.
	 * 1.8(무료)이하를 사용하고 있을 경우 실습은 넘어간다.
	 */
	private void myMethod() {
		System.out.println("private 메서드");
	}
	
	private static void mystaticMethod() {
		System.out.println("private static method");
	}
}

 실습 해보기 (Interface 두개를 상속받았는데 같은 default 메서드가 있을 경우)

package chapter9.interfaceex;

public interface Buy {
	void buy();
	
	default void order() {
		System.out.println("구매 주문");
	}
}
package chapter9.interfaceex;

public interface Sell {
	void sell();
	
	default void order() {
		System.out.println("판매 주문");
	}
}
package chapter9.interfaceex;

public class Customer implements Buy, Sell{

	@Override
	public void sell() {
		System.out.println("customer sell");
	}

	@Override
	public void buy() {
		System.out.println("customer buy");
	}

	@Override
	public void order() {
		System.out.println("customer order");
	}
	
	public void sayHello() {
		System.out.println("hello");
	}
}
​
package chapter9.interfaceex;

public class CustomerTest {
	public static void main(String[] args) {
		Customer customer = new Customer();
		customer.buy();
		customer.sell();
		customer.order();
		customer.sayHello();
		
		Buy buyer = customer;
		buyer.buy();
		buyer.order();
		
		Sell seller = customer;
		seller.sell();
		seller.order();
		
	}
}

 

참고자료

[패스트캠퍼스] 바이트디그리 Java & Spring Essential - 객체지향 프로그래밍 중급 수업 (박은종 강사님)
[코드] 객체지향 실습 코드 링크

 

 

 
 

 

 

반응형