[Java] 인터페이스

이지현·2022년 3월 24일
0
post-thumbnail

📕1. 인터페이스

1-1. 인터페이스란?

💡 추상메서드와 상수로만 이루어져있다.

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

그렇다면 인터페이스는 어떻게 사용하는 걸까? 아래에서 알아보자


1-2. 인터페이스 만들기

인터페이스를 사용해 간단한 계산기 프로그램을 만들어보자

public interface Calc
{
	// final 예약어를 사용하여 상수로 선언하지 않아도 인터페이스 변수는 컴파일 과정에서 상수로 자동 변환된다.
	double PI = 3.14;
	int ERROR = -999999999;

	// 인터페이스에서 선언한 메서드는 컴파일 과정에서 추상메서드로 자동 변환된다.
	int add(int num1, int num2);
	int substact(int num1, int num2);
	int times(int num1, int num2);
	int divide(int num1, int num2);
	
}////////////////// interface  
  • 원주율을 뜻하는 PI 변수 와 오류가 났을 때 사용할 ERROR 변수 , 그리고
    사칙연산을 수행하기 위해 add(), substract(), times(), divide() 메서드를 선언했다.

  • 이 메서드는 public abstract 예약어 를 사용하지 않아도 컴파일 과정에서 자동으로
    추상메서드로 변환된다.

  • 이 변수는 public static final 예약어 를 쓰지 않아도 모두 컴파일 과정에서 상수로 자동 변환된다.

그럼 이제 클래스에서 인터페이스를 사용해보자


1-3. 클래스에서 인터페이스 구현하기

public class Calculator implements Calc
{

}////////////////// class  
  • 이렇게 선언한 인터페이스를 클래스가 사용하는 것을 클래스에서 인터페이스를 구현한다 라고 표현한다.

  • 클래스 간 상속에서는 extends 예약어 를 사용하였지만
    인터페이스는 implements 예약어 를 사용한다.


이렇게 Calculator 클래스 에서 Calc 인터페이스 를 사용한다라고 정의 했으나 오류가 발생한다.

왜일까?

바로 Calc 인터페이스 의 추상메서드를 재정의하지 않아서 이다.
이렇게 되면 Calculator 클래스 는 추상클래스가 되버린다.

따라서 add(), subastract(), times(), divide() 메서드 를 모두 재정의 해줘야하는데

우선!

add(), subastract() 만 구현하고 나머지는 상속하는 클래스에서 재정의 하도록 추상클래스로 만들자


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;
	}
}////////////////// class  

이렇게 add(), subastract() 만 구현하고 나머지는 구현을 안했기에 Calculator 은 추상클래스이다.


1-4. 클래스 완성하고 실행하기

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

  • Calculator 추상클래스 를 상속받아 CompleteCalc 클래스 를 만든다.
  • 구현하지 않은 times(), divide() 추상 메서드 를 이 클래스에서 구현한다.
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(num2 != 0)
		{
			return num1/num2;
		}
		else
		{
			return Calc.ERROR;
		}
	}


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

클래스를 완성하였으니 실행을 해보자

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.substract(num1, num2));
		System.out.println(calc.times(num1, num2));
		System.out.println(calc.divide(num1, num2));

		calc.showInfo();
	}
}////////////////// class  
💡 출력 화면
15
5
50
2
Calc 인터페이스를 구현하였습니다.

📕2. 인터페이스와 다형성

2-1. 인터페이스의 역할

그러면 도대체 인터페이스는 왜 사용하는 걸까?

인터페이스는 공동작업에서 사용하는데 편리하다.
하나의 인터페이스를 만들어 놓으면 여러 클래스에서 인터페이스를 상속받아 재정의하여 사용할 수 있다.

2-2. 인터페이스의 역할 정리

  • 인터페이스를 사용하면 다형성을 구현하여 확장성 있는 프로그램을 만들 수 있다.
    즉, 클라이언트 프로그램을 많이 수정하지 않고, 기능을 추가하거나 다른 기능을 사용할 수 있다는 소리이다.

📕3. 인터페이스의 요소

3-1. 디폴트 메서드와 정적 메서드

💡 디폴트 메서드란?

  • 인터페이스에서 구현 코드까지 작성한 메서드이다.
  • 인터페이스를 구현한 클래스에 기본적으로 제공할 메서드인 것

💡 정적 메서드란?

  • 인스턴스 생성과 상관없이 사용할 수 있는 메서드이다.

디폴트 메서드나 정적 메서드를 추가했다고 해서 인터페이스가 인스턴스를 생성할 수 있는 것은 아니다!

그러면 인터페이스에 구현하는 디폴트 메서드와 정적 메서드가 무엇인지 ,
어떻게 호출하고 사용하는지 살펴보자!


3-2. 디폴트 메서드

  • 말 그대로 기본으로 제공되는 메서드
  • 인터페이스에서 구현하지만 , 이후 인터페이스를 구현한 클래스가 생성되면 그 클래스에서 사용할 기본 기능이다.
  • 디폴트 메서드를 선언할 때는 default 예약어를 사용해야 한다.

앞전에 배운 Calc 인터페이스를 활용하여 정수 계산기를 만들어보자

💻 Calc 인터페이스에 디폴트 메서드 구현하기 💻

public interface calc
{
	...
	default void description()
	{
		System.out.println("정수 계산기를 구현합니다.");
	}
}////////////////// interface  

디폴트 메서드를 구현한 인터페이스를 클래스에서 사용해보자

💻 디폴트 메서드를 구현한 인터페이스를 클래스에서 사용하기 💻

public class CalculatorTest
{
	public static void main(String[] args) {
		CompleteCalc calc = new CompleteCalc();
		calc.description();
	}

}////////////////// class  
💡 출력 결과

정수 계산기를 구현합니다.

이처럼 인터페이스에서 구현부가 있는 메서드를 디폴트 메서드라고 하며, 클래스에서 디폴트 메서드를 사용할 수 있다

그럼 , 디폴트 메서드는 재정의가 가능할까?

정답은 가능하다!


3-3. 정적 메서드

  • 정적 메서드는 static 예약어를 사용하여 선언한다
  • 클래스 생성과 무관하게 사용할 수 있다.
  • 정적 메서드를 사용할 때는 인터페이스 이름으로 직접 참조하여 사용한다.

3-4. private 메서드

  • 자바 9 이상부터 private 메서드를 구현할 수 있다.
  • private 메서드는 마찬가지로 재정의할 수 없다.
  • 하지만 static 예약어를 함께 사용할 수는 있다.

📕4. 인터페이스 활용하기

4-1. 한 클래스가 여러 인터페이스를 구현하는 경우

💡 인터페이스는 상속개념과는 조금 다르게 하나의 인터페이스를 여러개의 클래스가 구현할 수 있다.

두개의 인터페이스를 만들어 놓고 하나의 클래스에서 두개의 인터페이스를 사용해보자

💡 buy 인터페이스
public interface Buy
{
    void buy();
}
💡 sell 인터페이스
public interface Sell
{
    void sell();
}
💡 Customer 클래스가 두 인터페이스를 구현해보자
public class Customer implements Buy, Sell
{
    @Override
    public void sell() {
        System.out.println("구매하기");
    }


    @Override
    public void buy() {
        System.out.println("판매하기");
    }
}

이처럼 인터페이스는 한 클래스에서 다중으로 재정의할 수 있다.

Customer 클래스는 Buy형이자 Sell형이기도 한다.

아래에서 테스트 프로그램을 만들어보자!

💡 테스트 프로그램
public class CustomerTest {
    public static void main(String[] args) {
        Customer customer = new Customer();

        // Customer 클래스형인 customer를 Buy 인터페이스형인 buyer에 대입하여 형 변환하였다. buyer은 Buy인터페이스의 메서드만 호출이 가능하다.
        Buy buyer = customer;
        buyer.buy();


        // Customer 클래스형인 customer를 Sell 인터페이스형인 seller에 대입하여 형 변환하였다. seller는 Sell 인터페이스의 메서드만 호출이 가능하다.
        Sell seller = customer;
        seller.sell();

        if(seller instanceof Customer) {
            Customer customer2 = (Customer)seller;  // seller를 하위 클래스형인 Customer로 다시 형 변환하였다.
            customer2.buy();
            customer2.sell();
        }////////// if
    }///////////// main
}/////////////////////// class

4-2. 인터페이스 상속하기

  • 인터페이스 간에도 상속이 가능하다.
  • 인터페이스 간 상속은 구현코드를 통해 기능을 상속하는 것이 아니여서 형 상속이라고 부른다.

클래스 상속과 가장 큰 다른점은 무엇일까?

클래스는 하나의 클래스만 상속받을 수 있지만,

인터페이스는 여러 개를 동시에 상속받을 수 있다는 것이다.

한 인터페이스가 여러 인터페이스를 상속받으면 상속받은 인터페이스는 상위 인터페이스에 선언한 추상 메서드를 모두 가지게 된다.

그러면 ,
인터페이스가 인터페이스를 상속받을 때
implements 예약어를 사용할까 extends 예약어를 사용할까?

정답은?

extends 예약어를 사용한다.


4-3. 실무에서 인터페이스를 사용하는 경우

그러면 이러한 인터페이스는 실무에서 어떻게 사용되는 걸까?

인터페이스는 클래스가 제공할 기능을 선언하고 설계하는 것이다.
만약 여러 클래스가 같은 메서드를 서로 다르게 구현한다면 어떻게 해야할까?

우선 인터페이스에 메서드를 선언한 다음 인터페이스를 구현한 각 클래스에서 같은 메서드에 대해 다양한 기능을 구현하면된다.

이것이 인터페이스를 이용한 다형성의 구현이다.

profile
개발 공부 중인 지현이

0개의 댓글