2021. 7. 21. 20:45ㆍJava
이번 포스팅에선 추상 클래스와 인터페이스를 다뤄보도록 하겠습니다.
추상 클래스(abstract class)
추상 클래스는 '미완성 설계도'로서, 추상 메서드를 가진 클래스를 말합니다.
추상 클래스를 상속받아 다른 클래스 작성에 도움을 주기 위한 클래스이므로 인스턴스 생성은 불가능합니다.
구현이란 추상 메서드의 구현부를 만드는 행위를 말합니다.
구현 클래스는 추상 클래스를 상속받아서 추상 메서드의 구현부를 완성합니다.
단, 구현 클래스는 추상 클래스의 모든 추상 메서드를 구현해야되며 일부만 구현했다면 class 앞에 abstract 키워드를 붙여야 합니다.(안쓰면 error)
아래의 코드는 starcraft라는 게임의 유닛중 Marine, Tank, DropShip 이라는 세 개의 클래스를 정의한 코드입니다.
class Marine{
int x, y;
void move(int x, int y) { // 걸어서 이동하기 }
void stop() { // 정지하기 }
void stimPack() { // 스팀팩 사용하기 }
}
class Tank{
int x, y;
void move(int x, int y) { // 전차로 이동하기 }
void stop() { // 정지하기 }
void changeMode() { // 공격 모드로 전환하기 }
}
class DropShip{
int x, y;
void move(int x, int y) { // 날아서 이동하기 }
void stop() { // 정지하기 }
void load() { // 유닛 태우기 }
void unload() { // 유닛 내리기 }
}
추상 클래스를 사용하여 아래의 코드로 작성할 수 있습니다.
abstract class Unit{ // 추상 클래스
int x, y;
abstract void move(int x, int y);
void stop() { // 정지하기 }
}
class Marine extends Unit{
void move(int x, int y) { // 걸어서 이동하기 }
void stimPack() { // 스팀팩 사용하기 }
}
class Tank extends Unit{
void move(int x, int y) { // 전차로 이동하기 }
void changeMode() { // 공격 모드로 전환하기 }
}
class DropShip extends Unit{
void move(int x, int y) { // 날아서 이동하기 }
void load() { // 유닛 태우기 }
void unload() { // 유닛 내리기 }
}
추상 클래스를 사용해서 반복 코드를 줄이고 추상 클래스를 참고하여 클래스를 작성하기 때문에 코드 작성이 편해집니다.
또한 일반 클래스를 직접 상속하는 것보다 클래스간 결합도가 낮기 때문에 코드 변경에 더 유리하다는 장점이 있습니다.
추상 메서드(abstract method)
추상 메서드는 '미완성 메서드'로서, 구현부 {}가 없는 메서드입니다.
추상 클래스를 사용하는 이유
그렇다면 추상 클래스를 왜 사용하는 것일까요?
첫 번째는 추상 클래스를 구현하는 객체는 추상 메서드를 반드시 구현함을 보장한다는 것입니다.
여러 개발자들이 협업해야하는 상황에서, 추상 클래스는 클래스를 작성하는 가이드의 역할을 하기 때문에 공통된 필드나 메서드의 이름을 통일시켜서 개발의 일관성을 높이고 코딩 시간을 절약할 수 있습니다.
아래 그림처럼 설계 과정에서 추상 클래스를 단계별로 점점 구체적으로 작성해놓고 개발자는 상황에 맞게 골라서 구현 객체를 생성하는 것이 가능합니다.

두 번째는 여러 클래스에서 공통적인 부분을 따로 추출하기 위함입니다.
기존의 관련 없는 클래스들의 공통 부분을 추상 클래스를 이용하여 따로 추출하여 묶어서 관리하면, 변동 사항이 생겼을 때 해당 추상 클래스를 변경하여 자손 구현 객체들을 한꺼번에 변경할 수 있습니다.
그 덕분에 추상화된 코드는 구체화된 코드보다 변경에 더 유연하게 대응할 수 있습니다.
인터페이스(Interface)
인터페이스는 추상 메서드의 집합입니다.
구현된 것이 하나도 없는 설계도이며 모든 멤버가 public abstract 속성을 가지며 이는 생략 가능합니다.
인터페이스의 조상은 인터페이스만 가능하기 때문에 Object 클래스가 최고 조상이 아닙니다.
또한 모든 멤버의 구현부가 없기 때문에 충돌 걱정이 없어서 다중 상속이 가능합니다.
추상 클래스 vs 인터페이스
추상 클래스와 인터페이스는 비슷한듯 약간 다릅니다.
차이는 아래의 표와 같습니다.
추상 클래스 | 인터페이스 |
추상 메서드를 포함하는 미완성 클래스 | 추상 메서드만 가지는 미완성 설계도 |
인스턴스 변수 iv, 인스턴스 메서드 im, 생성자 사용 가능 | 인스턴스 변수 iv, 인스턴스 메서드 im, 생성자 사용 불가능 |
단일 상속만 지원 | 다중 상속 지원 |
Java가 클래스의 단일 상속만 지원하는 이유
우연히 부모 클래스 A와 B에서 선언부가 같고 구현부가 다른 메서드가 쌍으로 존재하면, 자식 클래스에서 어느 메서드를 사용하겠다는 건지 자바 컴파일러가 모르기 때문에 충돌이 일어납니다.
그래서 java에선 클래스의 단일 상속만 지원합니다.
인터페이스의 구현
인터페이스의 구현도 추상 클래스의 구현과 마찬가지로 구현 클래스에서 추상 메서드를 완성하는 것을 의미합니다.
다만, extends 대신에 implements 키워드를 사용합니다.
구현 클래스는 인터페이스의 모든 멤버를 구현해야하고 일부만 구현할 땐 추상 클래스로 간주됩니다.
부가적으로 JDK 1.8버전 부터 인터페이스 안에 static 메서드, 디폴트 메서드, 상수도 선언 가능하게 되었습니다.
단, 인터페이스의 설계 원칙에 어긋나게 되어 충돌 문제가 발생하게 되고 이를 해결하기 위해선 구현 클래스에서 어떤 메서드를 사용할 건지 오버라이딩으로 명시해야 합니다.
인터페이스를 이용한 다형성
인터페이스와 이를 구현한 객체는 부모/자식 관계를 가진다고 볼 수 있어서 다형성을 적용 가능합니다.
다형성의 장점을 그대로 사용 가능하며 메서드의 매개변수나 리턴 타입으로 인터페이스를 사용 가능합니다.
interface Fightable {
void move(int x, int y);
void attack(Fightable f);
}
class Fighter extends Unit implements Fightable {
public void move(int x, int y) { ~ }
public void attack(Fightable f) { ~ } // 매개변수 타입: interface
Fightable method() { // 리턴 타입: interface
Fighter f = new Fighter();
return f;
}
}
class Ex{
public static void main(String[] args){
Fightable f = new Fighter(); // 인터페이스타입 참조변수에 구현 객체 대입
f.attack(new Fighter());
}
}
인터페이스의 장점
인터페이스는 프로그래밍 세계에서 주로 '중간 역할'을 설명할 때 자주 사용되는 용어입니다.
예를 들면 운영체제(OS)가 있습니다.

OS는 애플리케이션과 컴퓨터 하드웨어 사이에 존재하며 두 객체간 '중간 역할'을 수행합니다.
컴퓨터가 통째로 바뀌어도 OS가 바뀌지 않는 이상 유저는 일관된 방식으로 컴퓨터를 사용할 수 있습니다.
또한 OS를 통해서 하드웨어들을 제어하기 때문에 내부적으로 일어나는 동작들을 유저가 알 필요가 없습니다.
Java의 인터페이스를 사용하면 클래스를 구현하는 쪽과 구현 클래스의 멤버를 호출하는 쪽을 분리 시킬 수 있습니다.
클래스를 구현하는 쪽은 interface를 implements 하는 방식으로 클래스를 구체화하고, 클래스를 호출하는 쪽은 interface의 멤버를 호출하여 기대하는 기능을 사용할 수 있습니다.
인터페이스를 사용하면 변경 사항에 더 유연하게 대응할 수 있습니다.
그림으로 표현하면 아래와 같습니다.

인터페이스 덕분에 B가 C로 변경되도 인터페이스로 감싸져있기 때문에 A는 따로 변경하지 않아도 됩니다.
이를 '느슨한 결합'이라고 합니다.
단 interface라는 과정을 하나더 거쳐야해서 성능이 저하될 수 있습니다.
정리하면, 아래와 같습니다.
- 클래스를 구현하는 쪽과 클래스 멤버를 호출하는 쪽의 '중간 역할'
- '느슨한 결합'으로 변경 사항에 유리
- 협업 과정에서 개발 일관성을 높이고 개발 시간 단축
JDBC란?
JDBC는 인터페이스들의 집합입니다.
애플리케이션과 DB사이에서 데이터를 전달하는 작업을 수행하는 자바 표준 API입니다.
어떤 DB를 사용하더라도 일관된 기능을 제공합니다.
Ref.
https://www.youtube.com/playlist?list=PLW2UjW795-f6xWA2_MUhEVgPauhGl3xIp
https://limkydev.tistory.com/188
https://ahnyezi.github.io/java/javastudy-8-interface/
'Java' 카테고리의 다른 글
[Java] 컬렉션 프레임워크 (3) (0) | 2021.07.28 |
---|---|
[Java] 컬렉션 프레임워크 (2) (0) | 2021.07.27 |
[Java] 컬렉션 프레임워크 (1) (0) | 2021.07.26 |
[Java] 객체지향 개념 (2) (0) | 2021.07.20 |
[Java] 객체지향 개념 (1) (0) | 2021.07.19 |