[이것이 자바다] 인터페이스 (Chapter. 8)

hhyeong_0·2023년 9월 9일
0

인터페이스 역할

: 사전적으로 두 장치를 연결하는 접속기를 의미

아래 그림과 같이 객체 A는 인터페이스를 통해 객체 B를 사용할 수 있다.
객체 A가 인터페이스의 메소드를 호출하면, 인터페이스는 객체 B의 메소드를 호출하고 그 결과를 받아 객체 A로 전달해준다.


위의 설명을 읽다보면 아래와 같은 생각이 들 수 있다.

"객체 A가 객체 B의 메소드를 직접 호출히면 간단할텐데 왜 중간의 인터페이스를 거치도록 하는 것일까?


답을 위해 위 사진과 같이 객체 B가 객체 C로 교체되는 상황을 가정해보겠다.
만약 객체 A가 인터페이스 없이 객체 B를 직접 사용한다면 객체 A의 소스 코드를 객체 B에서 객체 C로 변경하는 작업이 필요하다.
또한, 객체 B의 메소드 실행 결과가 객체 C의 메소드 실행 결과가 다르다면, 객체 A는 객체 B,C의 교체로 인해 다른 결과를 얻게 될 것이다!
=> 이러한 특징으로 인해 인터페이스를 이용해서 다형성을 구현하는 경우가 많다.


인터페이스와 구현 클래스 선언

public interface RemoteControl {
	public void turnOn();
}
public class Television implements RemoteControl {
	@Override
    public void turnOn(){
    	System.out.println("TV를 켭니다.");
    }
}

위에 선언한 RemoteControl 인터페이스로 Television을 사용할 수 있도록 Television 구현 클래스를 선언하였다.
위 코드 동작 흐름은 아래 사진과 같다.

- 변수 선언과 구현 객체 대입

인터페이스도 하나의 타입으로 변수의 타입으로 사용할 수 있다.
인터페이스는 참조 타입에 속하므로 인터페이스 변수에는 객체의 번지를 대입해야 한다.

RemoteControl rc = new Television();
rc.turnOn();

인터페이스 변수에 구현 객체가 대입이 되었다면, 위 코드처럼 변수를 통해 인터페이스의 추상 메소드를 호출할 수 있게 된다.
"인터페이스 변수를 통해 trunOn() 메소드가 호출되면, 실제로 실행되는 것은 Television에서 재정의된 turnOn() 메소드이다 !

  • 만약 Television이 implents RemoteControl로 선언되지 않았다면 RemoteControl 타입의 변수 rc에 대입할 수 없다 !


    rc 변수에는 RemoteControl을 구현한 어떠한 객체든 대입이 가능하다.
    만약 Audio 객체가 구현 객체라면 다음과 같이 Audio 객체로 교체해서 대입할 수도 있다.
RemoteControl rc = new Audio();
rc.turnOn();

동작 흐름은 아래 사진과 같다.


상수 필드

: 인터페이스는 public static final 특성을 갖는 불변의 상수 필드를 멤버로 가질 수 있다.
인터페이스에 선언된 필드는 모두 public static final 특성을 갖기 때문에 생략해도 자동적으로 컴파일 과정에서 붙여짐 !


다중 인터페이스 구현

: 구현 객체는 여러 개의 인터페이스를 implements 할 수 있다. 이 때 모든 인터페이스가 가진 추상 메소드를 재정의해야 함.

public class 구현클래스명 implements 인터페이스A, 인터페이스B {
	// 모든 추상 메소드 재정의
}
인터페이스A 변수 = new 구현클래스명(...);
인터페이스B 변수 = new 구현클래스명(...);

구현 객체가 어떤 인터페이스 변수에 대입되느냐에 따라 변수를 통해 호출할 수 있는 추상 메소드가 결정된다.


인터페이스 상속

: 인터페이스도 다른 인터페이스를 상속할 수 있으며, 클래스와는 달리 다중 상속을 허용한다. (이유는 페이지 맨 아래 참고)

public interface 자식인터페이스 extends 부모인터페이스1, 부모인터페이스2 {...}

자식 인터페이스의 구현 클래스는 자식 인터페이스의 메소드뿐만 아니라 부모 인터페이스의 모든 추상 메소드를 재정의해야 한다.
또한, 구현 객체는 다음과 같이 자식 및 부모 인터페이스 변수에 대입될 수 있다.

자식인터페이스 변수 = new 구현클래스(...);
부모인터페이스1 변수 = new 구현클래스(...);
부모인터페이스2 변수 = new 구현클래스(...);

타입 변환

: 인터페이스의 타입 변환은 인터페이스와 구현 클래스 간에 발생한다.
인터페이스 변수에 구현 객체를 대입하면 구현 객체는 인터페이스 타입으로 자동 타입 변환된다.
반대로 인터페이스 타입을 구현 클래스 타입으로 변환시킬 수 있는데, 이때는 강제 타입 변환이 필요하다.

  • 자동 타입 변환

    : 의미 그대로 자동으로 타입 변환이 일어나는 것을 말한다.
    자동 타입 변환은 다음과 같은 조건에서 일어난다.
인터페이스 변수 = 구현객체;


=> 부모 클래스가 인터페이스를 구현하고 있다면 자식 클래스도 인터페이스 타입으로 자동 타입 변환될 수 있다.

  • 강제 타입 변환

    : 캐스팅 기호를 사용해 인터페이스 타입을 구현 클래스 타입으로 변환시키는 것을 의미.
구현클래스 변수 = (구현클래스) 인터페이스변수;

* 구현 객체가 인터페이스 타입으로 자동 변환되면, 인터페이스에 선언된 메소드만 사용 가능하다.
그러나 인터페이스에 선언되지 않았지만 구현 클래스에 선언된 메소드를 사용하고 싶다면 캐스팅 기호를 사용해 원래 구현 클래스로 강제 타입변환한 뒤에 사용할 수 있다.


요약

현업에서는 상속보다는 인터페이스를 통해 다형성을 구현하는 경우가 더 많다.
상속의 다형성과 마찬가지로 인터페이스 역시 다형성을 구현하기 위해 재정의자동 타입 변환 기능을 이용한다.
인터페이스의 추상 메소드는 구현 클래스에서 재정의를 해야하며, 재정의되는 내용은 구현 클래스마다 다르다.
구현 객체는 인터페이스 타입으로 자동 타입 변환이 되고, 인터페이스 메소드 호출 시 구현 객체의 재정의된 메소드가 호출되어 다양한 실행 결과를 얻을 수 있다.








(추가) 왜 인터페이스의 다중 상속은 허용되고, 클래스는 안되는 걸까?

만약 자식클래스가 둘 이상의 클래스로부터 다중 상속을 받는다고 가정하자.

ParentA 부모 클래스에 love() 라는 메서드가 이미 정의되어있고, 마찬가지로 ParentB 라는 부모 클래스에도 love() 메서드가 존재한다. love() 메서드가 동일한 시그니처를 가진다면, 자식클래스는 둘 중 어느것을 상속받아야 할까?
(동일 시그니처 : 메서드의 접근 제어자, 리턴 타입, 메서드 명, 매개변수가 모두 동일함을 의미. 메서드 구현부는 같을수도, 다를 수도 있다.)

자식 클래스 입장에서는, love() 메서드를 상속받을 때, 어느 부모의 메서드를 상속받아야할 지 파악할 수 없게 된다. 이미 구현이 완료된 동일 시그니처의 메서드를 상속받는 일은 결국 불가능하다.

반면 인터페이스는 다중 상속이 가능하지만, 위의 문제를 피해 갈 수 있다. 왜냐하면 메서드가 정의되지 않았기 때문이다.
즉 선언된 형태의 메서드만 가지는 인터페이스는, 동일 시그니처의 메서드를 얼마든 상속받아도 아무런 문제가 발생하지 않는다.

해당 메서드는 아직 구현되지 않아 자식 클래스에서 새롭게 정의해야 하기 때문이다.


+ 추상 클래스는 최소 하나 이상의 추상 메소드를 가진 클래스를 가진다. 따라서 인터페이스와의 차이점미리 구현된 메소드를 가지냐 아니냐의 차이!

참조:
이것이 자바다 교육 현장에서 가장 많이 쓰이는 JAVA 프로그래밍의 기본서 [ 개정판 ] - 신용권, 임경균 저 | 한빛미디어
https://junior-datalist.tistory.com/213

profile
배우고 기록하자 !

0개의 댓글