Language/JAVA

열번째날 [인터페이스]

구일일구 2022. 8. 4. 20:42
반응형

목차

1. 인터페이스의 역할

2. 인터페이스 선언

3. 인터페이스 구현

4. 인터페이스 사용

5. 타입 변환과 다형성

6. 인터페이스 상속

7. 디폴트 메소드와 인터페이스 확장


[인터페이스] like 음식점 메뉴판 

인터페이스 안에는 추상 메소드 밖에 없음. 애초에 키워드를 안넣어도 됨

추상 클래스 위에 인터페이스가 있음. 

인터페이스는 기능이 없음 인터페이스는 구현. 다형성 작업 가능

전체적인 틀을 잡는 느낌

 

1. 인터페이스의 역할

* 인터페이스란?

- 개발 코드와 객체가 서로 통신하는 접점 : 개발 코드는 인터페이스의 메소드만 알고 있으면 ok

(음식점에서 주방과 통신하는 것은 '메뉴판' = 인터페이스)

* 인터페이스 역할

- 개발 코드가 객체에 종속되지 않게 : 객체가 교체할 수 있도록 하는 역할

- 코드 변경 없이 리턴값 또는 실행 내용이 다양해 질 수 있음 : 다형성


2. 인터페이스 선언

* 인터페이스 선언

- 인터페이스 이름 : 규칙에 따라

- 소스 파일 생성 : 이름과 대소문자가 동일한 소스파일 생성

[public] interface 인터페이스명 {...}

 

*  구성 멤버 : 상수, 추상 메소드, 디폴트 메소드, 정적 메소드

1) 상수 필드 선언 : 상수필드 static final이 붙은 것

- 인터페이스는 상수 필드만 선언 가능

- 인터페이스에 선언된 필드는 모두 public static final

- 상수명은 대문자로 작성

- 선언과 동시에 초기값 지정 : static{} 블록 작성 불가 , static{} 으로 초기화 불가

int MIN_VOLUME = 0;

 

2) 추상 메소드 선언 : abstract method 

- 인터페이스를 통해 호출된 메소드는 최종적으로 클래스가 가지고 있는 객체에서 실행

: 기본적으로 실행 블록이 없는 추상 메소드로 선언 : 틀만 잡는다 

: public abstract을 생략해도 자동적으로 컴파일 과정에서 붙게 됨

void setVolume(int volume);

 

3) 디폴트 메소드 선언 : 추상 메소드와 구분하기 위해 default를 붙임 : default method 

- default 키워드를 반드시 붙여야 함

- 실행 블록을 가지고 있는 메소드

- public 생략해도 자동으로 붙음

default void setMute(boolean mute){
	if(mute){
		System.out.println("무음 처리합니다.");
	} else{
		System.out.println("무음 해제합니다.");
	}
}

 

4) 정적 메소드 선언 : static method 

- 클래스의 정적메소드와 완전 동일함

- public 생략 가능

static void changeBattery(){
	System.out.println("건전지를 교체합니다.");
}

3. 인터페이스 구현

* 인터페이스는 자체적으로 사용할 수 X : 추상 메소드 때문에 (완성되지 않았기 때문에)

 

* 클래스를 만들어서 인터페이스를 구현해야한다.

 

* 추상 메소드를 오버라이딩 해야한다 : 아무런 내용이 없기 때문에 새로 정의해야 한다. 

 

* 구현 클래스를 쓰려면, 당연히 구현 객체를 생성해야 한다.

 

* 구현 클래스 선언 : implements 키워드

 

* 오버라이딩을 하려면, 부모클래스.인터페이스가 가지고 있는 것보다 더 넓은 범위로 접근제한자를 할 수 있으나,

좁은 범위로 접근제한자로 할 수 없다.

 

* 인터페이스의 모든 추상 메소드를 재정의하는 실체 메소드를 작성해야 한다.

- 일부만 재정의한다면, 클래스를 추상 클래스로 선언하고 메소드는 abstract 키워드 붙이면 된다.

 

* 익명 구현 객체

- 일회성의 구현 객체를 만들기 위해 소스 파일을 만들지 않고, 구현 객체를 만들 수 있는 방법

- 인터페이스에 선언된 모든 추상 메소드들의 실체 메소드를 작성해야 한다.

- 추가적으로 필드와 메소드 선언이 가능하지만, 익명 객체 안에서만 사용가능하다.

- 인터페이스를 구현한 클래스의 이름이 없다

- 안드로이드, 모바일에서 많이 나옴


4. 인터페이스 사용

인터페이스 변수;
변수 = 구현객체;

또는

인터페이스 변수 = 구현객체;

RemoteControl rc;
rc = new Television();

 

* 추상 메소드 사용

RemoteControl rc = new Television();
rc.turnOn();	//Television의 turnOn() 실행
rc.turnOff();	//Television turnOff() 실행

 

* 디폴트 메소드 사용

- 인터페이스만으로는 사용 불가 : 구현 객체가 인터페이스에 대입되어야 호출할 수 있는 인스턴스 메소드

- 모든 구현 객체가 가지고 있는 기본 메소드라고 생각하기: 필요에 따라 구현 클래스가 디폴트 메소드 재정의해 사용

- RemoteControl 인터페이스의 setMute() 디폴트 메소드를 호출하는 방법

setMute() 메소드를 호출하려면 RemoteControl의 구현 객체가 필요

➡️ Television 객체를 인터페이스 변수에 대입한 후 setMute() 호출 가능

✅ 비록 setMute()가 Television에 선언되지 않았지만, Television 객체가 없다면 setMute()도 호출 불가능

RemoteControl rc = new Television();
rc.setMute(true);

 

* 정적 메소드 사용 

- 인터페이스로 바로 호출 가능

public class RemotecontrolExample{
	public static void main(String[] args){
		RemoteControl.changeBattery();
	}
}

5. 타입 변환과 다형성

* 다형성 : 하나의 타입에 여러 가직 객체 대입해 다양한 실행 결과를 얻는 것

 

* 다형성을 구현하는 기술

- 상속 또는 인터페이스의 자동 타입 변환

- 오버라이딩

 

* 다형성의 효과

- 다양한 실행 결과 얻을 수 있음

- 객체 부품화해서 유지보수 용이

 

* 자동 타입 변환 : 프로그램 실행 도중에 자동으로 타입 변환이 일어나는 것

- 구현 객체가 인터페이스 타입으로 변환

- 인터페이스 구현 클래스를 상속해서 자식 클래스를 만들었다면, 자식 객체도 인터페이스로 자동 타입 변환 가능

 

 

 

* 필드의 다형성

인터페이스
public void roll();	//roll()메소드 호출 방법 설명
구현 클래스(1)
@Override
public void roll(){
System.out.println("한국 타이어가 굴러갑니다.")	//인터페이스 구현
}
구현 클래스(2)
@Override
public void roll(){
System.out.println("금호 타이어가 굴러갑니다.")
}
필드의 다형성
public class Car {
	//Tire 부분을 한국 타이어로 만들면, 나중에 금호타이어로 못만듦.
	Tire frontLeftTire = new HankookTire();
	Tire frontRightTire = new HankookTire();
	Tire backLeftTire = new HankookTire();
	Tire backRightTire = new HankookTire();
	
	void run() {
		frontLeftTire.roll();
		frontRightTire.roll();
		backLeftTire.roll();
		backRightTire.roll();
	}
}
필드 다형성 테스트
public static void main(String[] args){
Car myCar = new Car();

myCar.run();

myCar.frontLeftTire = new KumhoTire();
myCar.frontRightTire = new KumhoTire();

myCar.run();

- 필드 타입으로 타이어 인터페이스를 선언하게 되면 필드값으로 한국 타이어나 금호타이어 객체를 대입할 수 있다(자동 타입 변환)

- Car 객체를 생성한 후, 초기값으로 대입한 구현 객체 대신 다른 구현 객체를 대입할 수도 있다 : 타이어 교체

- 앞바퀴에 어떠한 타이어 구현 객체가 저장되어도 Car 객체는 타이어 인터페이스에 선언된 메소드만 사용하므로 전혀 문제X

- Car의 run() 메소드 수정 없이도 다양한 roll() 메소드의 실행 결과를 얻을 수 있음 ➡️ 필드의 다형성!

 

* 인터페이스 배열로 구현 객체 관리

Tire[] tires = {
new HankookTire(),
new HankookTire(),
new HankookTire(),
new HankookTire()
}

- tires[0], tires[1], tires[2], tires[3]과 같이 인덱스로 표현되어 대입이나 제어문에서 활용하기 쉬워짐

 

* 매개변수의 타입이 인터페이스 인 경우

- 어떠한 구현 객체도 매개값으로 사용 가능하며, 객체에 따라 실행결과가 달라진다

- 구현 객체에 따라 메소드 실행 결과가 달라짐

 

* 강제 타입 변환(Casting)

- 구현 클래스 ➡️ 인터페이스 자동 타입 변환 후 / 인터페이스 ➡️ 구현 클래스로 강제 타입 변환하는 것

즉 ,구현 ➡️ 인터페이스 ➡️ 다시 구현

- 필요한 이유? 구현 클래스 타입에 선언된 다른 멤버 사용하기 위해서

구현클래스 변수 = (구현클래스) 인터페이스변수;

 

* 객체 타입 확인 : instanceof

- 어떤 구현 객체가 변환되어 있는지 알 수 없는 상태에서 무작정 강제 타입 변환을 하면, 예외 발생 할 수 있음!

- 인터페이스로 변환된 객체가 이게 맞는지 확인하기 위해서 사용

인터페이스변수 instanceof 구현클래스

6. 인터페이스 상속

* 인터페이스 간 상속 가능 : 다중 상속 허용

public interface 하위인터페이스 extends 상위인터페이스1, 상위인터페이스2 {...}

 

하위인터페이스 변수 = new 구현클래스(...);
상위인터페이스1 변수 = new 구현클래스(...);
상위인터페이스2 변수 = new 구현클래스(...);

- 하위 인터페이스의 구현 클래스는 추상 메소드 모두 재정의해야 함

 


7. 디플트 메소드와 인터페이스 확장

* 디폴트 메소드가 있는 인터페이스 상속 : 부모 인터페이스의 디폴트 메소드를 자식 인터페이스에서 활용 방법

- 디폴트 메소드를 단순히 상속만 받음

- 디폴트 메소드를 재정의해서 실행 내용 변경

- 디폴트 메소드를 추상 메소드로 재선언

반응형