7.7 인터페이스(Interface)
1. 인터페이스(Interface)란?
- 일종의 추상클래스이며 추상클래스(미완성 설계도)보다 추상화 정도가 높다.
- 실제 구현된 것이 전혀 없는 기본 설계도를 생각하면 된다.
- 추상메서드와 상수만을 멤버로 가질 수 있다.
- 인스턴스를 생성할 수 없고, 클래스 작성에 도움을 줄 목적으로 사용된다.
- 미리 정해진 규칙에 맞게 구현하도록 표준을 제시하는 데 사용된다.
결론: 인터페이스는 추상 메서드의 집합이다.(프로그래밍의 관점)
1-(2) 추상클래스와 인터페이스의 차이
- 추상클래스: 일반 클래스 + 추상 메서드
- 인터페이스: 구현된 것이 아무것도 없는 것(추상메서드와 상수만 쭈욱 늘여놓은 것)
2. 인터페이스의 작성
- class대신 interface를 사용한다는 것 외에는 클래스 작성과 동일하다.
- 하지만 구성요소(멤버)는 추상메서드와 상수만 가능하다.
2-(1) 인터페이스의 기본적인 구조
interface 인터페이스이름{
public static final 타입 상수이름 = 값; //상수(부수적인 것)
public abstract 메서드이름(매개변수목록); //추상 메서드(핵심)
}
- 상수: 부수적인 것
- 추상 메서드: 핵심 요소
- 변수 iv, cv: 사용불가
- public: 모든 인터페이스의 멤버는 public
- public / abstract -> 생략 가능
- final / static: 상수는 항상 파이널이기 때문에 생략 가능
3. 인터페이스의 상속
- 인터페이스도 클래스처럼 상속이 가능하다.(클래스와 달리 다중상속을 허용한다.)
- 인터페이스는 Object 클래스와 같은 최고 조상이 없다.
- 인터페이스의 조상은 인터페이스만 가능하다.(Object가 최고 조상이 아니다.)
package javaStandard;
//다중상속을 허용하는 interface
interface Fightable extends Movable, Attackable{ }
//인터페이스의 조상은 인터페이스만 가능하기 때문에 extend 쓰지 않아도 됨.생략가능
interface Movable{
//지정된 위치로 이동하는 기능의 메서드
void move(int x, int y);
}
interface Attackable{
void attack(Unit u);
}
4. 인터페이스의 구현
- 인터페이스를 구현하는 것은 클래스를 상속받는 것과 같다.
- 인터페이스에 정의된 추상메서드를 완성해야 한다.
- 상속과 구현이 동시에 가능하다.
class 클래스이름 implements 인터페이스이름 {
//인터페이스에 정의된 추상메서드를 모두 구현해야 한다.(implements를 사용)
//추상메서드는 extend를 통해서 상속 받아 구현.
}
//인터페이스를 전부 구현하는 경우
class Fighter implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
publiv void attack(Unit u) { /* 내용 생략 */ }
}
//인터페이스를 일부 구현하는 경우
abstract class Fighter implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
//public abstract void attack (Unit u); 생략되어 있는 내용임
//추상메서드를 가지고 있어서 추상 클래스표현을 해주어야 한다.
}
5. 인터페이스를 이용한 다형성
- 인터페이스 타입의 변수로 인터페이스를 구현한 클래스의 인스턴스를 참조할 수 있다.
- 인터페이스를 메서드의 매개변수 타입으로 지정할 수 있다.
- 인터페이스를 메서드의 리턴타입으로 지정할 수 있다.
package javajungsuk;
abstract class Unit{
int x, y;
abstract void move(int x, int y);
void stop() {
System.out.println("멈춥니다.");
}
}
interface Fightable{ //인터페이스의 모든 메서드는 예외 없이 public abstract.
void move(int x, int y); // public abstract 생략됨
void attack(Fightable f);// public abstract 생략됨
}
class Fighter extends Unit implements Fightable {
//오버라이딩 규칙: 조상(public)보다 접근제어자가 좁으면 안 된다.
public void move(int x, int y) { //public을 붙이지 않으면 default로 범위가 조상보다 좁아서 오류 난다!!!
System.out.println("["+x+", "+y+ "]로 이동");
}
public void attack(Fightable f){
System.out.println(f+"를 공격");
}
}
public class FighterTest {
public static void main(String[] args) {
//Fighter f = new Fighter();
//Unit f2 = new Fighter(); Unit에는 attack()이 없어서 호출 불가
Fightable f = new Fighter();
f.move(100,200);
f.attack(new Fighter());
f.stop();
}
}
<참조 변수의 형변환과 다형성을 같이 녹여낸 코드>
package javajungsuk;
abstract class Unit{
int x, y;
abstract void move(int x, int y);
void stop() {
System.out.println("멈춥니다.");
}
}
interface Fightable{ //인터페이스의 모든 메서드는 예외 없이 public abstract.
void move(int x, int y); // public abstract 생략됨
void attack(Fightable f);// public abstract 생략됨
}
class Fighter extends Unit implements Fightable {
//오버라이딩 규칙: 조상(public)보다 접근제어자가 좁으면 안 된다.
public void move(int x, int y) { //public을 붙이지 않으면 default로 범위가 조상보다 좁아서 오류 난다!!!
System.out.println("["+x+", "+y+ "]로 이동");
}
public void attack(Fightable f){
System.out.println(f+"를 공격");
}
Fightable getFightable() {
Fighter f = new Fighter(); //Fighter를 생성해서 반환
return f; //return (Fightable)f; 형변환이 생략됨
}
}
public class FighterTest {
public static void main(String[] args) {
Fighter f = new Fighter();
Fightable f2 = f.getFightable();//반환타입이 일치해야 한다.
}
}
6. 인터페이스의 장점
- 개발 시간을 단축시킬 수 있다.
- 표준화가 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
- 독립적인 프로그래밍이 가능하다.
▸ 두 대상(객체) 간의 '연결, 대화, 소통'을 톱는 '중간 역할'을 한다.
interface = inter(between) + face (사이 + 얼굴/대상)
컴퓨터 - 하드웨어
윈도우(GUI) - 인터페이스
※ 사용자가 컴퓨터를 직접 사용하기에는 어려움이 많기 때문에 이를 쉽게 사용할 수 있도록 인터페이스(GUI와 같은)가 존재하고 또 하드웨어가 바뀌어도 GUI 인터페이스만 바뀌지 않으면 하드웨어를 사용자는 문제 없이 사용이 가능하다.
▸선언(설계)와 구현을 분리시킬 수 있게 한다. (선언- 껍데기 / 구현 - 알맹이)
- 인터페이스 덕분에 B가 변경되어도 A는 바꾸지 않아도 된다.(느슨한 결합)
👉 왜냐하면 A는 껍데기만 사용하기 때문에 알맹이가 C로 바뀌든 뭐로 바뀌든 상관이 없게 된다. (A의 변경이 일어나지 않는다.)
< 직접적인 관계의 두 클래스(A-B) >
package javajungsuk;
class A {
public void methodA(B b) {
b.methodB();
}
}
class B {
public void methodB() {
System.out.println("methodB()");
}
}
class InterfaceTest{
public static void main(String args[]) {
A a = new A();
a.methodA(new B());
}
}
↓
<간접적인 관계의 두 클래스(A-B)>
package javajungsuk;
class A{
public void methodA(I i) {
i.methodB();
}
}
interface I { void methodB(); }
class B implements I{
public void methodB() {
System.out.println("methodB()");
}
}
A 클래스가 B를 사용하다 I를 사용하게 되어 B와 관계가 없고 인터페이스와 관계를 갖게 된다.
1. 개발 시간을 단축할 수 있다. - 인터페이스의 장점
#1. B가 완성될 때까지 A는 기다려야 한다.
#2. B가 완성되지 않아도 A는 interface를 사용하기 때문에 기다릴 필요가 없다 -> 개발 시간을 단축시켜준다.
2. 변경에 유리한 설계가 가능하다. - 인터페이스의 장점
A가 직접 B를 사용하지 않고 Interface(껍데기)를 사용하기 때문에 C(알맹이)로 변경이 되어도 상관이 없다.
3. 표준화가 가능하다. - 인터페이스의 장점
# JDBC(인터페이스 집합)을 사용해서 기존 DB가 변경될 때 javaApplication의 변경(의존성이 높기 때문)이 불가피 했었던 상황을 해결했다. -> 표준화
4. 서로 관계 없는 클래스들을 관계를 맺어줄 수 있다. - 인터페이스의 장점
void repair(Tank t){
//탱크를 수리한다.
}
void repair(Dropship d){
//탱크를 수리한다.
}
void repair(CroundUint gu){
// 매개변수로 넘겨진 지상유닛을 수리한다.
이때의 문제는 기계가 아닌 사람과 공중유닛인 Dropship은 이를 사용할 수 없다는 것이다.
}
↓
package javaStandard;
//인터페이스를 사용해서 오버로딩을 다 해줄 필요를 줄인 경우
interface Repairable {}
class scv extends Groundunit implements Repairable{
//
}
class Tank extends Groundunit implements Repairable{
//
}
class Dropship extends Groundunit implements Repairable{
//
}
# 이때 인터페이스는 다중상속이 허용되기 때문에 각 유닛들이 어떤 상속계층도에 있든지 상관 없이 상속이 가능하다.
# 형제관계도 아닌 SCV / Tank / Dropship이 Repairable을 구현했다는 공통점으로 묶어 사용이 가능하게 해준다
void repair(Repairable r) { // repairable을 구현한 애들을 넣어줄 수 있다.
if (r instanceof unit) {
Unit u = (unit)r;
while(u.hitPoint!=u.MAX_HP) {
u.hitPoint++; //유닛의 HP를 증가시킨다
}
}
}//repair(Repairable r)
7. 인터페이스의 이해
8. 디폴트 메서드(default method)와 static 메서드
- 인터페이스에 새로운 메서드(추상 메서드)를 추가하면?
-> 이 인터페이스를 구현한 기존의 모든 클래스가 이 메서드를 구현해야 한다.
- 이 문제를 해결하기 위해 '디폴트 메서드'를 고안
- 디폴트 메서드는 추상 메서드의 기본 구현을 제공한다. 그래서 몸통 { }을 가지고 있으며, 앞에 'default'를 붙이고 항상 public이다. (생략이 가능하다.)
티폴트 메서드가 기존의 메서드와 충돌할 때의 해결책
1. 여러 인터페이스의 디폴트 메서드 간의 충돌
- 인터페이스를 구현한 클래스에서 디폴트 메서드를 오버라이딩해야 한다.
2. 디폴트 메서드와 조상 클래스의 메서드 간의 충돌
- 조상 클래스의 메서드가 상속되고, 디폴트 메서드는 무시된다.
- 인터페이스에 새로운 메서드(추상 메서드)를 추가하기 어렵다.
<인터페이스에 디폴트 메스드를 추가하게 된 배경>
기존의 인터페이스에 새로운 추상메서드를 넣을 경우 기존 인터페이스를 구현한 클래스들의 내부에 많은 변경이 생기기 때문에 이를 해결하기 위해서 디폴트 메서드가 인터페이스에 사용이 가능하게 되었고(원칙은 추상메서드 이외의 디폴트 메소드 등을 사용하면 기존의 인터페이스 원칙을 위반하게 된다.)
결과적으로 몸통을{} 만들어주기 때문에 기존의 인터페이스를 구현한 클래스 내에 다시 수정해서 구현해야 할 필요가 없어진다.
<인터페이스에 새로운 메서드 추가가 어려운 것을 해결하기 위에 사용된 디폴트 메서드>
package javaStandard;
inteface MyInterface{
void method(); /* 추상 메서드 --> 기존 인터페이스에서는 추상 메서드만 허용
{} 몸통이 없는 메서드를 추상메서드라고 한다. */
default void newMethod() {} /*몸통을 가지고 있는 디폴트 메소드를 추가해서
기존의 인터페이스의 기존 문제였던 새로운 메소드(추상 메소드) 추가가 어려운
문제를 해결했다. */
}
인터페이스란?
= 추상메서드의 집합이다. (추상메서드가 인터페이스의 핵심임)
인터페이스의 구현이란?
= 인터페이스의 추상메서드 몸통{} 만들기(미완성 설계도를 완성하는 것이다.)
추상클래스와 인터페이스 구현의 차이점.
-> 미완성 설계도 완성이라는 점에서 같은 점임.
추상클래스와 인터페이스의 공통점은?
= 추상 메서드를 가지고 있다(미완성 설계도이다.)
추상클래스와 인터페이스의 차이점은?
= 인터페이스는 iv를 가질 수 없다. (상수는 가질 수 있다.)
'Java > 객체지향' 카테고리의 다른 글
[객체지향][자바의 정석] - 7.8 내부 클래스(Inner class) (0) | 2021.12.14 |
---|---|
객체지향 개념 끝 (0) | 2021.12.14 |
[객체지향][자바의 정석] - 7.6 추상클래스(Abstract class) (0) | 2021.11.28 |
[객체지향][자바의 정석] - 7.5 다형성 (0) | 2021.11.15 |
[객체지향][자바의 정석] - 7.4 제어자 (0) | 2021.11.11 |