[작성일: 2023. 01. 30]
목차
인터페이스(Interface)
- 추상 메서드의 집합(프로그래밍 관점)
- 구현된 것이 전혀 없는 설계도 껍데기(모든 멤버가 public) ➡️객체를 만들 수 없음.
- 하나의 시스템을 구성하는 두 개의 요소, 또는 두 개의 다른 시스템이 상호 작용을 할 수 있게 하는 접속 경계
- 접속하기 위한 하드웨어, 소프트웨어, 조건, 규약 등을 포괄적으로 가리킴.
interface 인터페이스명 { // iv, cv 등 변수는 가질 수 없음.
public static final 타입 상수이름 = 값; // 상수
public abstract 메서드명(매개변수 목록); // 추상 메서드({}이 없음.)
} // 모든 인터페이스의 멤버는 public만을 가짐.
interface PlayingCard {
public static final int SAPDE = 4;
final int DIAMOND = 3;
static int HEART = 2;
int CLOVER = 1; // public static final 일부or전부 생략 가능
public abstract String getCardNumber();
/* public abstract 생략 가능 */ String getCardKind();
}
Java의 인터페이스
- 프로그램과 프로그램을 연결해 주는 것
- [규제]
- 특정한 규약에 의해 개발하도록 하는 목적
- 클래스가 인터페이스를 사용하려면 반드시 인터페이스가 만들라고 한 메서드들을 전부 구현해야 함.
- 인터페이스의 메서드를 구현하지 않으면 컴파일이 되지 않음.
인터페이스를 왜 만들었을까?
ex)
계산기 기능 개발을 하던 도중,
계산기 자체는 A가 개발하고 계산기를 이용하는 어플은 B가 개발을 했다.
동시에 개발을 하다 보니 B는 A가 잘 개발할 것을 가정하고 어플 개발을 진행한다.
➡️ 나중에 보니 A는 add(a, b) 메서드이고, B는 add(int a[]) 메서드로 개발하였다.
인터페이스 사용법
[public] // [규제]이기 때문에 무조건 public
[public] interface 인터페이스명 {} // 클래스 자리에 interface 넣기
[public][static][final] 자료형 상수명 = 값;
[public] 리턴타입 메서드명(인자);
[public] default 리턴타입 메서드명(인자) {}
[public] static 리턴타입 메서드명(인자) {}
class 클래스명 implements 인터페이스명 {}
// 클래스 생성 시 가장 복잡한 형태
class 클래스명 extends 부모클래스 implements 인터페이스1, 인터페이스2 ... throws Exception
// 간단 예제
interpace Interface1 {
public void myMethod1();
}
class Class1 implements Interface1 {
public void myMethod1() {
내가 구현; (내용이 없어도 존재해야 함)
}
}
인터페이스의 상속
- 인터페이스의 조상은 인터페이스만 가능(Object가 최고 조상이 아님.)
- 다중 상속(조상이 여러 개) 가능 (추상 메서드는 충돌해도 문제없음.➡️구현부가 없기 때문.)
- 부모 클래스의 기능을 자식 클래스가 물려받는 것.
interface Fightable extends Movale, Attackabe { } // 다중 상속
interface Movable { // 인터페이스의 조상은 인터페이스만 가능
/* 지정된 위치(x, y)로 이동하는 기능의 메서드*/
void move(int x, int y);
}
interface Attackable {
/* 지정된 대상(u)을 공격하는 기능의 메서드*/
void attack(Unit u);
}
// 인터페이스끼리 상속
interface I3 { void x(); }
interface I4 extends I3 { void y(); }
class C2 implements I4 {
void x() {
}
void y() {
}
}
인터페이스의 구현
- 인터페이스에 정의된 추상 메서드를 완성(구현)하는 것
- 인터페이스의 구현과 상속은 완전히 다름.
- 인터페이스 구현은 자식 클래스가 반드시 만들도록 강제하는 것.
- 클래스 선언은 class, 인터페이스 선언은 interface
- 클래스 상속은 extends, 인터페이스 구현은 implements
- 하나의 클래스가 여러 개의 인터페이스도 구현 가능함.
class 클래스 이름 implements 인터페이스 이름 {
// 인터페이스에 정의된 추상메서드를 모두 구현해야 함.
}
class Fighter implements Fightable {
// 모든 추상 메서드가몸통이 생겼기 때문에 abstract 없음.
// Fighter클래스는 Fightable 인터페이스를 구현했다고 표현함.
public void move(int x, int y) { /*내용 생략*/ }
public void attack { /*내용 생략*/ }
}
// 일부만 구현하는 경우 클래스 앞에 abstract를 붙여야 함.
abstract class Fighter implements Fightable {
public void move(int x, int y) { /*내용 생략*/ }
}
//하나의 클래스가 여러 개의 인터페이스 구현 가능
interface I1 { void x(); }
interface I2 { void y(); }
class C1 implements I1, I2{
void x() {
}
void y() {
}
}
Q&A
Q. 인터페이스란?
A. 추상 메서드의 집합
abstract clss Player {
abstract void play(int pos);
abstract void stop();
}
Q. 인터페이스의 구현이란?
A. 인터페이스의 추상메서드 몸통{} 만들기(미완성 설계도 완성하기)
class AudioPlayer extends Player { // 추상클래스 구현
void play(int pos) { /* 내용 생략 */ }
void stop() { /* 내용 생략 */ }
}
class Fighter implements Fightable { // 인터페이스 구현 구분 잘 하기
public void move(int x, int y) { /* 내용 생략 */ }
public void attack(Unit u) { /* 내용 생략 */ }
}
Q. 추상 클래스와 인터페이스의 공통점은?
A. 추상 메서드를 가지고 있음.(미완성 설계도)
Q. 추상 클래스와 인터페이스의 차이점은?
A. 인터페이스는 iv, 생성자, im을 가질 수 없음. (상수, static메서드, default메서드, 추상메서드만 가질 수 있음.)
인터페이스를 이용한 다형성
- 인터페이스도 구현 클래스의 부모로 생각할 수 있음.
- 인터페이스 타입 매개변수는 인터페이스를 구현한 클래스의 객체만 가능함.
- 인터페이스를 메서드의 리턴타입으로 지정할 수 있음.(Fightable 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 뜻)
Unit u = new Fighter(); // 가능. 조상클래스
Fightable f = new Fighter(); // 가능. 인터페이스
// 자손객체 -> 조상클래스 가리키는 것 가능
interface Fightable {
void move(int x, int y);
void attack (Fightable f);
// attack의 매개변수 타입이 인터페이스임.
// 매개변수의 타입이 인터페이스인 경우는 인터페이스를 구현한 클래스의 객체만 받겠다는 뜻.
}
f.move(100, 200);
f.attackr(new Fighter());
// Fighter의 객체가 아무리 많아도 인터페이스에 선언된 멤버 2개만 사용할 수 있음.
//인터페이스를 리턴타입으로 지정 가능
Fightable method() {
...
Fighter f = new Fighter();
return f; // 인터페이스를 구현한 객체 반환
// return new Fighter(); 와 같은 문장임.
}
abstract class Unit2 {
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 Unit2 implements Fightable {
// 오버라이딩 규칙: 조상보다 접근제어자 범위가 좁으면 안 됨.
public void move(int x, int y); {
System.out.println(x + "," + y + "로 이동");
}
public void attack(Fightable f); {
System.out.println(f + "를 공격");
}
}
Fightable getFightable() { // 메서드 추가
Fighter f = new Fighter();
return (Fightable)f;
public class FighterTest {
public static void main(String[] args) {
Fighter f = new Fighter();
Fightable f2 = f.getFightable(); // 반환타입하고 일치해야 함.
}
}
인터페이스의 장점
- 두 대상(객체) 간의 '연결, 대화, 소통'을 돕는 '중간 역할'을 함.
- 선언(설계)과 구현을 분리시킬 수 있게 함. ➡️ 개발 시간 단축, 변경에 유리하고 유연한 설계 가능
- 표준화가 가능함.(JDBC➡️인터페이스의 집합)
- 서로 관계없는 클래스들을 관계 맺어줄 수 있음.
// 선언과 구현을 분리시킬 수 있음.
class B {
public void method() {
System.out.println("methodInB");
} //껍데기+알맹이 -> 유연하지 못 하고 변경에 불리함.
}
// ⬇️ 새로운 interface 선언, 껍데기
Interface I {
public void method(); // class B의 선언부만 떼어내기
}
// ⬇️
// 구현, 알맹이
class B implements I {
public void method() {
System.out.println("methodInB");
}
}
//2. 인터페이스 덕분에 B가 변경되어도 다른 클래스(A)는 안 바꿀 수 있음.
//느슨한 결합 ↔️ 강한결합
//직접적인 관계의 두 클래스
// (A-B)// A(User) ➡️ B(Provider)
class A {
public void methodA(B b) {
b.methodB(); // B클래스의 메서드 호출
}
}
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());
}
}
// 위의 코딩보다는 B클래스를 인터페이스로 분리하는 것이 유연한 코딩임.
// A(User) ➡️ I
class A {
pullic void methodB(I i ) { // I를 사용하도록 바꿈
i.methodB();
}
}
interface I { // 껍데기, 추상메서드
void methodB();
}
class B implements I { //알맹이, 인터페이스 구현
public void methodB() {
System.out.println("methodB()");
}
}
class C implements I { // B를 C로만 변경해주면 되고 A를 건들 필요 없음
public void methodB() {
System.out.println("methodB() int C");
}
}
// 서로 관계없는 클래스들을 관계맺어 줄 수 있음
Interface Repairablee {}
class SCV extends GroundUnit implements Repairable {
// ...
}
class Tank extends GroundUnit implements Repairable {
// ...
}
class Dropship extends GroundUnit implements Repairable {
// ...
}
// Repairable 구현
void repair(Repairable r) {
if (r instanceof Unit) {
Unit u = (Unit)r;
while(u.hitPoint!=u.MAX_HP) {
u.hitPoint++; // Unit의 HP를 증가시킴.
}
}
🐣 해당 게시글은 자바의 정석(남궁성 님) 영상으로 함께 공부하며 요약/정리한 글입니다.
🐣 입문 개발자가 작성한 글이므로 틀린 내용이나 오타가 있을 수 있습니다.