자바에서는 추상 메서드(abstract method)라는 개념이 있습니다. 추상 메서드란 아래와 같이 메서드의 선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것 입니다.
abstract void example1(int num1, int num2);
abstract void example2(String name);
이와 같은 추상 메서드를 포함하고 있는 클래스를 추상 클래스(abstract class), 오직 추상 메서드와 상수만을 멤버로 가지는 클래스를 인터페이스(interface)라고 합니다.
이와 같이 메서드를 미완성 상태로 선언해 놓는 것이 무슨 의미가 있을까요?
<추상클래스 구현 및 상속>
그것은 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문에 조상클래스에서는 선언부만 작성해 놓고, 실제 내용은 상속받는 클래스에서 구현하도록 비워놓는 것입니다.
abstract class Unit {
int hp;
int pos;
abstract void play(int pos);
abstract void attack(Player Animy);
void stop(){
return 0;
}
}
class Warrior extends Unit {
void play(int pos){
this.pos++;
};
void attack(Player Animy){
Animy.hp--;
};
}
abstract class AbstractArcher extends Unit {
void attack(Player Animy){
Animy.hp -= 2;
}
}
ㅣ위의 예시를 보면 Player 추상 클래스를 상속받은 Warrior 클래스와 AbstractArcher 클래스가 각자 상황에 맞게 attack 추상 메서드를 구현한 것을 알 수 있습니다. 여기서 추상 클래스를 상속받을 때 추상 메서드 중 하나라도 구현하지 않으면 상속받은 클래스도 추상 클래스로 지정해 주어야 합니다.
<인터페이스 구현 및 상속>
인터페이스는 오직 추상 메서드로만 이루어진 추상화 정도가 더 높은 개념입니다. 때문에 그 자체만으로 사용되기보다는 다른 클래스를 작성하는데 도움을 줄 목적으로 사용됩니다.
인터페이스의 멤버들은 다음과 같은 제약사항이 있습니다.
- 모든 멤버변수는 public static 이어야 하며, 이를 생략할 수 있다.
- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다. 단, static메서드와 디폴트 메서드는 제외
interface Movable {
void move(int x, int y);
}
interface Attackable {
void attack(Unit u);
}
interface Fightable extends Movable, Attackable {}
class Fighter extends Unit implements Fightable{
public void move(int x, int y){/*내용생략*/}
public void attack(Unit u){/*내용생략*/}
}
위와 같이 인터페이스는 인터페이스부터 로만 상속받을 수 있으며, 클래스와 달리 다중상속이 가능하다. 또한 인터페이스를 구현하는 것은 implements 키워드를 사용하여 구현하고 인터페이스의 메서드 중 일부만 구현한다면, abstract를 붙여서 추상클래스로 선언해야 합니다.
그리고, 위의 Fighter 클래스와 같이 상속과 구현을 동시에 할 수 있습니다.
<인터페이스 다형성>
인터페이스 역시 이를 구현한 클래스의 조상이라 할 수 있으므로 해당 인터페이스 타입의 참조변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환도 가능합니다. 인터페이스 Fightable을 Fighter 클래스가 구현했을 때
Fightable f = (Fightable) new Fighter();
또는
Fightable f = new Fighter();
와 같이 참조할 수 있다는 것입니다.
Fightable method() {
...
Fighter f = new Fighter();
return f;
}
또한 리턴타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미합니다.
<인터페이스의 장점과 이해>
인터페이스를 사용하는 이유와 그 장점을 정리해 보면 다음과 같습니다.
- 개발시간을 단축시킬 수 있다.
- 표준화가 가능하다.
- 서로 관계없는 클래스들에게 관계를 맺어줄 수 있다.
- 독립적인 프로그래밍이 가능하다.
1. 개발시간을 단축시킬 수 있다.
일단 인터페이스가 작성되면, 이를 사용해서 프로그램을 작성하는 것이 가능하다. 메서드를 호출하는 쪽에서는 메서드의 내용에 관계없이 선언부만 알면 되기 때문이다. 그리고 동시에 다른 한쪽에서는 인터페이스를 구현하는 클래스를 작성하게 하면, 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 양쪽에서 동시에 개발을 진행할 수 있다.
2. 표준화가 가능하다.
프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 다음, 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 보다 일관되고 정형화된 프로그램 개발이 가능하다.
3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
서로 상속관계에 있지도 않고, 같은 조상클래스를 가지고 있지 않은 서로 아무런 관계도 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어줄 수 있다.(다형성이 생긴다)
4. 독립적인 프로그래밍이 가능하다.
인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제구현에 독립적인 프로그램을 작성하는 것이 가능하다. 클래스와 클래스 간의 직접적인 관계를 인터페이스를 이용해서 간접적인 관계로 변경하면, 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능하다.
class A{
public void methodA(B b){
b.method();
}
}
class B{
public void methodB(){
print("methodB()");
}
}
만약 위와 같은 코드가 있다고 하면 클래스 A를 작성하려면 클래스 B가 이미 작성되어 있어야 합니다.

또한 methodB()의 선언부가 변경된다면, 이를 사용하는 클래스 A도 변경되어야 합니다. 이러한 단점을 보완하기 위해 인터페이스를 사용한다면
interface I{
public abstract void methodB();
}
class B implements I{
public void methodB(){
print("methodB()");
}
}
class A{
public void methodA(I i){
i.methodB();
}
}
위와 같이 A와 B가 I를 두고 간접적인 관계로 바뀌어 클래스 B의 변경이 A에 영향을 미치치 못하게 됩니다.

methodB()를 구현한 클래스가 바뀌거나 심지어 구현이 되었는지 조차도 클래스 A는 상관이 없게 됩니다. 클래스 A는 오직 인터페이스 I의 영향만 받게 되어 껍데기(인터페이스 I) 안에 어떤 알맹이(클래스)가 있는지 몰라도 되게 됩니다.

이렇듯 인터페이스는 체계적인 개발과 유지보수에 있어서 강력한 도구로 작용합니다.
참조
자바의 정석(남궁 성)
틀린 부분이 있으면 지적해 주시면 감사하겠습니다.
'개발 > Java' 카테고리의 다른 글
[Java] 지네릭스(generics) (0) | 2024.05.25 |
---|---|
[Java] 오토 박싱 & 오토 언박싱 (1) | 2024.02.27 |
[Java] hashCode와 equals 오버라이드(hashCode는 주소값이 아니다.) (1) | 2023.12.16 |
[Java]부동소수점수(2진 체계의 부호 표현법) (0) | 2023.12.16 |