일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- puppeteer
- 알고리즘
- 인접행렬
- javascript
- TIL
- GraphQL
- 프로그래머스
- Spring
- html
- winston
- REST API
- 코딩테스트
- Interceptor
- typescript
- 자료구조
- 탐욕법
- MySQL
- Deep Dive
- node.js
- css
- java
- Kubernetes
- JWT
- OOP
- LifeCycle
- Linux
- nestjs
- dfs
- 인접리스트
- bean
- Today
- Total
처음부터 차근차근
[Java] Interface 본문
Interface란?
interface는 일종의 추상클래스입니다.
추상메서드와 상수만을 멤버로 가질 수 있으며, 그 외의 다른 어떠한 요소도 허용하지 않습니다.
추상클래스를 '미완성 설계도'라고 한다면, 인터페이스는 밑그림만 그려져 있는 '기본 설계도'라고 할 수 있습니다.
interface 인터페이스이름 {
public static final 타입 상수이름 = 값;
public abstract 메서드이름(매개변수 목록);
}
- 순스 추상 클래스의 특징을 모두 가집니다.
- 인스턴스 생성 불가
- 상속 시 모든 메서드를 오버라이딩 해야 한다.
- 주로 다형성을 위해 사용된다.
- 인터페이스에도 클래스처럼 접근제어자로 public 또는 default만 사용할 수 있다.
- 모든 메서드는 public abstract이어야 하며, 이를 생략할 수 있습니다.
- 모든 멤버 변수는 public static final이어야 하며, 이를 생략할 수 있습니다.
- 인터페이스는 다중 구현(다중 상속)을 지원합니다.
간단한 예제
저번 추상 클래스에서 한 모델을 이번에는 인터페이스로 작성해보겠습니다.
참고 : 클래스 상속 관계는 UML에서 실선을 사용하지만, 인터페이스 구현(상속) 관계는 UML에서 점선을 사용한다.
package poly.ex5;
public interface InterfaceAnimal {
void sound();
void move();
}
package poly.ex5;
public class Dog implements InterfaceAnimal {
@Override
public void sound() {
System.out.println("멍멍");
}
@Override
public void move() {
System.out.println("개 이동");
}
}
인터페이스를 상속 받을 때는 extends 대신에 implements라는 구현이라는 키워드를 사용해야 합니다. 따라서 인터페이스는 상속이라 하지 않고 구현이라 합니다.
package poly.ex5;
public class Cat implements InterfaceAnimal {
@Override
public void sound() {
System.out.println("야옹");
}
@Override
public void move() {
System.out.println("고양이 이동");
}
}
package poly.ex5;
public class Caw implements InterfaceAnimal {
@Override
public void sound() {
System.out.println("음머");
}
@Override
public void move() {
System.out.println("소 이동");
}
}
package poly.ex5;
public class InterfaceMain {
public static void main(String[] args) {
//인터페이스 생성 불가
//InterfaceAnimal interfaceMain1 = new InterfaceAnimal();
Cat cat = new Cat();
Dog dog = new Dog();
Caw caw = new Caw();
soundAnimal(cat);
soundAnimal(dog);
soundAnimal(caw);
}
//동물이 추가 되어도 변하지 않는 코드
private static void soundAnimal(InterfaceAnimal animal) {
System.out.println("동물 소리 테스트 시작");
animal.sound();
System.out.println("동물 소리 테스트 종료");
}
}
저번 포스팅에서 설명한 순수 추상 클래스와 예제 거의 유사하며, 프로그램 코드, 메모리 구조상 모두 똑같습니다.
즉, 인터페이스는 순수 추상 클래스와 비슷하다고 생각하면 됩니다.
왜 구현인가??
- 부모 클래스의 기능을 자식 클래스가 "상속" 받는다고 표현합니다. 즉, 이름 그대로 부모의 기능을 물려 받는 것이 목적입니다.
- 인터페이스는 모든 메서드가 추상 메서드입니다. 따라서 물려받을 수 있는 기능이 없고, 오히려 인터페이스에 정의한 모든 메서드를 자식이 오버라디이 해서 기능을 구현해야 합니다. 따라서 구현이라고 표현합니다.
Interface를 사용해야 하는 이유
- 제약
- 인터페이스를 만드는 이유는, 인터페이스를 구현하는 곳에서 인터페이스의 메서드를 반드시 구현해라는 규약을 주는 것입니다.
- 그러나 순수 추상 클래스의 경우, 누군가 그곳에 실행 가능한 메서드를 끼워 넣을 수 있습니다. 이렇게 되면 순수 추상 클래스가 아니게 됩니다. 따라서 interface는 이러한 문제를 원천 차단할 수 있습니다.
- 다중구현
- 자바에서 클래스 상속은 부모 하나만 지정할 수 있지만, 반면에 인터페이스는 부모를 여러명 두는 다중 구현(다중 상속)이 가능합니다.
Interface - 다중 구현
클래스는 다중 상속을 지원하지 않지만, 인터페이스는 다중 상속(다중 구현)을 지원합니다.
- InterfaceA, B 모두 동일한 methodCommon()을 가지고 있습니다. 그리고 Child는 두 인터페이스를 구현했습니다. 상속 관계의 경우 두 부모 중에 어떤 한 부모의 methodCommon()을 사용해야 할 지 결정해야 하는 다이아몬드 문제가 발생합니다.
- 하지만 인터페이스 자신은 구현을 가지지 않습니다. 대신 인터페이스를 구현한 곳에서 해당 기능을 모두 구현해야 합니다.
- 동일한 메서드가 존재해도, 구현은 Child가 합니다. 그리고 오버라이딩에 의해 Child에 있는 methodCommon()이 호출됩니다.
- 이런 이유로 인하여 인터페이스는 다이아몬드 문제가 발생하지 않으며, 다중 구현을 허용합니다.
(못 믿겠으면 직접 해봐야겠쥐~?)
package poly.diamond;
public interface InterfaceA {
void methodA();
void methodCommon();
}
package poly.diamond;
public interface InterfaceB {
void methodB();
void methodCommon();
}
package poly.diamond;
public class Child implements InterfaceA, InterfaceB{
@Override
public void methodA() {
System.out.println("Child.methodA");
}
@Override
public void methodCommon() {
System.out.println("Child.methodCommon");
}
@Override
public void methodB() {
System.out.println("Child.methodB");
}
}
package poly.diamond;
public class DiamondMain {
public static void main(String[] args) {
InterfaceA a = new Child();
a.methodA();
a.methodCommon();
InterfaceB b = new Child();
b.methodB();
b.methodCommon();
}
}
인터페이스의 상속
인터페이스는 인터페이스로부터만 상속 받을 수 있으며, 클래스와는 달리 다중 상속이 허용됩니다.
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
interface Fightable extends Movable, Attackable {}
클래스와 인터페이스 활용
클래스 상속과 인터페이스 구현을 함께 사용하는 예를 알아보겠습니다.
extends를 통한 상속은 하나만 할 수 있고, implements를 통한 인터페이스는 다중 구현 할 수 있기 때문에 둘이 함께 나온 경우 extends가 먼저 나와야 합니다.
package poly.ex6;
public abstract class AbstractAnimal {
public abstract void sound();
public void move() {
System.out.println("동물이 이동합니다.");
}
}
package poly.ex6;
public interface Fly {
void fly();
}
package poly.ex6;
public class Dog extends AbstractAnimal {
@Override
public void sound() {
System.out.println("멍멍");
}
}
package poly.ex6;
public class Chicken extends AbstractAnimal implements Fly {
@Override
public void sound() {
System.out.println("꼬끼오");
}
@Override
public void fly() {
System.out.println("닭 날기");
}
}
package poly.ex6;
public class Bird extends AbstractAnimal implements Fly{
@Override
public void sound() {
System.out.println("짹짹");
}
@Override
public void fly() {
System.out.println("새 날기");
}
}
package poly.ex6;
public class SoundFlyMain {
public static void main(String[] args) {
Dog dog = new Dog();
Bird bird = new Bird();
Chicken chicken = new Chicken();
soundAnimal(dog);
soundAnimal(bird);
soundAnimal(chicken);
flyAnimal(bird);
flyAnimal(chicken);
// flyAnimal(dog); // 개는 Fly를 구현하지 않았으므로 컴파일 에러
}
//AbstractAnimal 사용 가능
private static void soundAnimal(AbstractAnimal animal) {
System.out.println("동물 소리 테스트 시작");
animal.sound();
System.out.println("동물 소리 테스트 종료");
}
//Fly 인터페이스가 있으면 사용 가능
private static void flyAnimal(Fly fly) {
System.out.println("날기 테스트 시작");
fly.fly();
System.out.println("날기 테스트 종료");
}
}
Fly 인터페이스를 구현한 Bird, Chicken을 전달해서 flyAnimal을 실행할 수 있습니다.
인터페이스의 장점
- 개발 시간을 단축시킬 수 있습니다.
- 표준화가 가능합니다.
- 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있습니다.
- 독립적인 프로그래밍이 가능합니다.
- 선언과 구현을 분리시킬 수 있기 때문에 실제 구현에 독립적인 프로그램을 작성하는 것이 가능합니다.
참고
자바8에 등장한 default 메서드를 사용하면 인터페이스도 메서드를 구현할 수 있다. 하지만 이것은 예외적으로 아주 특별한 경우에만 사용해야 한다. 자바9에서 등장한 인터페이스의 private 메서드도 마찬가지이다. 지금 학습 단계에서는 이 부분들을 고려하지 않는 것이 좋다. 이 부분은 뒤에서 따로 다룬다.
참고
자바의 정석_기초편
'Language > Java' 카테고리의 다른 글
[Java] 불변 객체 (0) | 2024.07.26 |
---|---|
[Java] Object 클래스 (0) | 2024.07.24 |
[Java] abstract 추상 클래스 & 추상 메서드 (1) | 2024.01.02 |
[Java] 다형성 (0) | 2024.01.01 |
[Java] final (1) | 2023.12.31 |