728x90
한 클래스가 여러 인터페이스를 구현하는 경우
- 한 클래스가 여러 클래스를 상속받으면 메서드 호출이 모호해지는 문제가 발생할 수 있습니다.
- 하지만 인터페이스의 구현은 상속과는 다르게 한 클래스가 여러 인터페이스를 구현할 수 있습니다.

- 위 그림을 보면 Customer 클래스는 Buy 와 Sell 두 인터페이스를 구현합니다.
- 이를 코드로 나타내면 다음과 같습니다.
public interface Buy {
void buy();
}
public interface Sell {
void sell();
}
public class Customer implements Buy, Sell {
@Override
public void sell() {
System.out.println("판매하기");
}
@Override
public void buy() {
System.out.println("구매하기");
}
}
- 인터페이스는 구현 코드나 멤버 변수를 가지지 않기 때문에 여러 개를 동시에 구현할 수 있습니다.
- 이게 무슨 말이냐면, 인터페이스를 구현하는 클래스에서 어차피 추상 메서드를 모두 구현해야 하기 때문에 구현하는 인터페이스들에 동일한 이름의 추상 메서드가 있어봤자 의미가 없다는 것을 의미합니다.
- 결국 구현하는 두 인터페이스에서 이름이 같은 메서드가 선언되었다고 해도 구현은 클래스에서 이루어지기 때문에, 어떤 메서드를 호출해야 하는지 모호하지 않습니다.
- 위 코드에서 Sell 인터페이스와 Buy 인터페이스를 구현한 Customer 클래스는 Buy 형이자 Sell 형이기도 합니다.
- 이런 특성을 보여주는 다음과 같은 코드를 확인할 수 있습니다.
public class CustomerTest {
public static void main(String[] args) {
Customer customer = new Customer();
Buy buyer = customer;
buyer.buy();
Sell seller = customer;
seller.sell();
if(seller instanceof Customer) {
Customer customer2 = (Customer)seller;
customer2.buy();
customer2.sell();
}
}
}
- 위 코드를 보면 Customer 형으로 선언된 customer 변수를 Buy와 Sell 형으로 대입할 수 있다.
- 위와 같이 형 변환이 일어나면 해당하는 형에서 사용 가능한 메서드와 상수만 사용 가능합니다.
- 또한 상속에서와 마찬가지로 원래의 인스턴스 자료형으로 다운 캐스팅하기 위해서는 instanceof 를 사용하여 본래 인턴스 자료형으로 안전하게 변환할 수 있습니다.
두 인터페이스의 디폴트 메서드가 중복되는 경우
두 인터페이스의 정적 메서드가 중복되는 경우에는 문제가 되지 않는다.
- 정적 메서드는 인스턴스 생성과 상관없이 사용할 수 있습니다.
- Customer 클래스가 Buy, Sell 두 인터페이스를 구현하고 Buy 인터페이스와 Sell 인터페이스에 똑같은 pay( ) 라는 정적 메서드가 있었다면 어떻게 될까요?
- 정답은 아무런 문제가 발생하지 않는다는 겁니다.
- 왜냐하면 Buy.pay( ) 와 Sell.pay( ) 로 호출하는 명이 다르기 때문입니다.
두 인터페이스의 디폴트 메서드가 중복되는 경우에는 문제가 된다.
- 왜냐하면 디폴트 메서드는 인스턴스를 생성해야 호출할 수 있는 메서드이기 때문에 이름이 같으면 모호성이 발생하여 문제가 발생합니다.
- "Duplicate default methods named order with the ... 이 오류 메시지는 디폴트 메서드가 중복되었으니 두 인터페이스를 구현하는 Customer 클래스에서 재정의하라는 뜻입니다.
- Customer 클래스에서 디폴트 메서드를 재정의하면, Customer 클래스를 생성하여 사용할 때 재정의된 메서드가 호출됩니다.
- 여기서 주의할 점이 하나 있습니다.
- 이전에 배운 자바 가상 메서드 원리가 바로 여기서도 적용된다는 점입니다.
- 다음 코드를 보겠습니다.
public class CustomerTest {
public static void main(String[] args) {
Customer customer = new Customer();
Buy buyer = customer;
buyer.buy();
buyer.order(); // 가상 메서드 발생
Sell seller = customer;
seller.sell();
seller.order(); // 가상 메서드 발생
if(seller instanceof Customer) {
Customer customer2 = (Customer)seller;
customer2.buy();
customer2.sell();
customer2.order();
}
}
}
- 인스턴스에 order 라는 default 메서드를 만든 이후에 Test 코드입니다.
- 위 코드에서 Customer 가 Buy 형으로 변환되고 buyer.order( )를 호출하면 Buy 에 구현한 디폴트 메서드가 아닌 Customer 클래스에 재정의한 메서드가 호출됩니다.
- 이전에 배운 자바 가상 메서드 원리와 완벽히 동일합니다.
인터페이스 상속하기
- 인터페이스 간에도 상속이 가능합니다.
- 인터페이스 간 상속은 구현 코드를 통해 기능을 상속 하는 것이 아닙니다.
- 그렇기에 인터페이스 간 상속을 형 상속(type inheritance) 라고 합니다.
- 클래스의 경우에 하나의 클래스에 하나의 클래스만 상속받을 수 있었지만, 인터페이스는 여러 개를 동시에 상속받을 수 있습니다.
- 한 인터페이스가 여러 인터페이스를 상속 받으면 상속 받은 인터페이스는 상위 인터페이스에 선언한 추상 메서드를 모두 가지게 됩니다.
- 다음 코드를 보면서 배워보겠습니다.
public interface X {
void x();
}
public interface Y {
void y();
}
- 우선 상속 받을 인터페이스 2개를 만들었습니다.
public interface MyInterface extends X, Y {
void myMethod();
}
- 2개 인터페이스를 상속받는 인터페이스를 만들었습니다.
- 그렇다면 이 myMethod 인터페이스를 구현한 클래스는 몇개의 추상 메서드를 구현해야 할까요?
- 정답은 3개입니다.
인터페이스 구현과 클래스 상속 함께 쓰기
- 한 클래스에서 클래스 상속과 인터페이스 구현을 모두 할 수도 있습니다.
- Queue 인터페이스를 구현하고 shelf 클래스를 상속받는 BookShelf 클래스를 구현해보면서 배워보겠습니다.
public class Shelf {
protected ArrayList<String> shelf;
public Shelf() {
shelf = new ArrayList<String>();
}
public ArrayList<String> getShelf() {
return shelf;
}
public int getCount() {
return shelf.size();
}
}
- 먼저 상속 받을 Shelf 클래스를 구현했습니다.
public interface Queue {
void enQueue(String title); // 배열이 맨 마지막에 추가
String deQueue(); // 배열의 맨 처음 항목 제거 후 해당 값 반환
int getSize(); // 현재 Queue에 있는 개수 반환
}
- 구현될 Queue interface 를 구현했습니다.
public class Bookshelf extends Shelf implements Queue {
@Override
public void enQueue(String title) {
shelf.add(title);
}
@Override
public String deQueue() {
return shelf.remove(0);
}
@Override
public int getSize() {
return getCount();
}
}
- Shelf 클래스를 상속받고 Queue 인터페이스를 구현한 BookShelf 클래스를 구현했습니다.
- ArrayList 라는 클래스를 사용한 것을 볼 수 있는데, 앞으로 자바 프로그램을 개발하면서 이미 제공되고 있는 클래스나 인터페이스를 사용한 프로그램을 자주 접하게 됩니다.
- 특히 실무에서는 프레임워크나 기존 소스 코드를 사용해 개발하는 경우가 많습니다.
실무에서 인터페이스를 사용하는 경우
- 인터페이스는 기본적인 용도가 해당 인터페이스를 구현한 클래스가 제공할 기능을 선언하고 설계하는 것입니다.
- 만약 여러 클래스가 같은 메서드를 서로 다르게 구현한다면 어떻게 해야 할까요?
- 인터페이스에 메서드를 선언(추상 메서드로 자동 변환 public abstract) 한 다음에 인터페이스를 구현한 각 클래스에서 같은 메서드에 대해 다양한 기능을 구현하면 됩니다.
- 이것이 바로 인터페이스를 이용한 다형성의 구현입니다.
- 이런 경우를 생각해 봅시다.
- 어느 회사에서 시스템을 개발하였는데, 이 시스템은 자료를 저장하기 위해 데이터베이스를 사용합니다.
- 그런데, 고객 사들이 사용하는 데이터 베이스가 모두 다른 겁니다.
- 이런 경우 데이터 베이스와 연관되는 코드만 따로 모아서 작업을 해주어야 합니다.
- 그 후 데이터베이스 기능을 수행할 인터페이스를 정의한 다음 인터페이스 저으이에 맞게 여러 데이터베이스 관련 모듈을 개발하면 됩니다.
- 이렇게 인터페이스를 잘 정의하는 것이 확장성 있는 프로그램을 만드는 시작입니다.
JDBC와 인터페이스
- JDBC 는 Java DataBase Connectivity 의 약자입니다.
- 자바와 데이터베이스를 연결해 주는 역할을 합니다.
- 자바와 데이터베이스를 연결하려면 여러 기능을 수행해야 하는데 그 중 하나가 Connection을 생성하고 연결하는 것입니다.
- JavaDoc 에서 Connection을 찾아보면 다음과 같은 내용을 볼 수 있습니다.
- 자바와 데이터베이스를 연결하기 위해 사용하는 Connection은 인터페이스입니다.
- 이 인터페이스에는 여러 메서드들이 미리 구현되어 있으며 이들 메서드를 사용하여 데이터베이스에 접근하는 자바 프로그램을 구현하면 됩니다.
- 그렇다면 Connection 과 같은 JDBC 인터페이스는 누가 구현한 걸까요?
- 이 인터페이스는 오라클, MySQL 등 데이터베이스 프로그램을 만드는 회사에서 구현합니다.
- 데이터베이스 회사가 자신의 회사 데이터베이스에 맞게 구현한 클래스 파일 묶음인 .jar 라이브러리를 제공하기 때문에, 우리는 프로그래밍을 하면서 제공된 라이브러리를 로딩하여 Connection 인터페이스에 선언된 메서드를 사용하기만 하면 됩니다.
- 정리해보면 JDBC 는 자바에서 데이터베이스를 어떻게 사용할 것인지를 기술한 명세, 즉 인터페이스이자 약속인 셈입니다.
'[그린컴퓨터] Server > JAVA(객체 지향 프로그래밍)' 카테고리의 다른 글
| 인터페이스 요소 살펴보기 { 인터페이스 상수, 디폴트 메서드와 정적 메서드, 디폴트 메서드, private 메서드 } (0) | 2023.06.04 |
|---|---|
| 인터페이스와 다형성 { 인터페이스의 역할, 인터페이스와 다형성, 클라이언트가 클래스를 사용하는 방법 } (0) | 2023.06.04 |
| 인터페이스란 { 구현 코드가 없는 인터페이스, 클래스에서 인터페이스 구현하기, 인터페이스 구현과 형 변환 } (0) | 2023.06.02 |
| final 예약어 { 상수를 의미하는 final 변수, 상속할 수 없는 final 클래스, TDD } (0) | 2023.06.01 |
| 템플릿 메서드 응용하기 { 예제 이해하기, 클래스 기능과 관계, 클래스 설계하기, 추상 클래스와 다형성 } (0) | 2023.06.01 |