추상 메서드(abstract method)
선언부만 작성하고 구현부는 작성하지 않은 채로 남겨 둔 것이 추상 메서드이다.
메서드를 이와 같이 미완성 상태로 남겨 놓는 이유는 메서드의 내용이 상속받는 클래스에 따라 달라질 수 있기 때문에 조상 클래스에서는 선언부만을 작성하고, 주석을 덧붙여 어떤 기능을 수행할 목적으로 작성되었는지 알려 주고, 실제 내용은 상속받는 클래스에서 구현하도록 비워 두는 것이다.
/* 주석을 통해 어떤 기능을 수행할 목적으로 작성하였는지 설명한다 */
abstract 리턴타입 메서드이름();
추상 클래스로부터 상속받는 자손 클래스는 오버 라이딩을 통해 조상인 추상 클래스의 추상 메서드를 모두 구현해주어야 한다. 만일 조상으로부터 상속받은 추상 메서드 중 하나라도 구현하지 않는다면, 자손 클래스 역시 추상 클래스로 지정해주어야 한다.
abstract class Player{ // 추상클래스
abstract void play(int pos); // 추상 메서드
abstract void stop(); // 추상 메서드
}
class AudioPlayer extends Player{
void play(int pos) {/* 내용 생략*/} // 추상 메서드를 구현
void stop() { /*내용 생략 */} // 추상 메서드를 구현
}
abstract class AbstactPlayer extends Player {
void play(int pos) { /* 내용 생략 */} // 추상 메서드를 구현
}
메서드를 작성할 때 실제 작업내용인 구현부보다 더 중요한 부분이 선언 부이다.
추상 클래스 작성
상속이 자손 클래스를 만드는데 조상 클래스를 사용하는 것이라면, 이와 반대로 추상화는 기존의 클래스의 공통부분을 뽑아내서 조상 클래스를 만드는 것이라고 할 수 있다.
class Marine { // 보병
int x, y; // 현재 위치
void move(int x, int y) {/* 지정된 위치로 이동 */}
void stop() {/* 현재 위치에 정지 */}
void stimPack() {/* 스팀팩을 사용한다.*/}
}
class Tank { //탱크
int x, y; // 현재 위치
void move(int x, iont y){/* 지정된 위치로 이동 */}
void stop() {/* 현재 위치에 정지 */}
void changeMode() {/* 공격모드를 변환한다.*/}
}
class Dropship{ // 수송선
int x, y; // 현재 위치
void move(int x, iont 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, iont y) {/* 지정된 위치로 이동 */}
void changeMode() {/* 공격모드를 변환한다.*/}
}
class Dropship extends Unit { // 수송선
void move(int x, iont y) {/* 지정된 위치로 이동 */}
void load() {/* 선택된 대상을 태운다.*/}
void unload() {/* 선택된 대상을 내린다.*/}
}
각 클래스의 공통부분을 뽑아내서 Unit클래스를 정의하고 이로부터 상속받도록 하였다.
Unit클래스는 다른 유닛을 위한 클래스를 작성하는데 재활용이 될 수 있을 것이다.
인터페이스
인터페이스
인터페이스는 일종의 추상 클래스이다.
인터페이스는 추상 클래스처럼 추상 메서드를 갖지만 추상 클래스보다 추상화 정도가 높아서 추상 클래스와 달리 몸통을 갖춘 일반 메서드 또는 멤버 변수를 구성원으로 가질 수 없다.
인터페이스는 구현된 것은 아무것도 없고 밑그림만 그려져 있는 ‘기본 설계도’라 할 수 있다.
interface 인터페이스이름{
public static final 타입 상수 이름 = 값;
public abstract 메서드이름(매개변수목록);
}
//interface에도 클래스처럼 접근 제어자로 public 또는 default만 사용할 수 있다.
"interface를 이용하여, 개발 코드를 직접 수정하지 않고도, 사용하고 있는 객체만 변경할 수 있도록 하기 위함입니다." (중요 중요!!)
인터페이스 제약사항
- 모든 멤버 변수는 public static final 이어야 하며, 이를 생략할 수 있다.
- 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.
단, static메서드와 디폴트 메서드는 예외(JDK1.8부터)
인터페이스에 정의된 모든 멤버에 예외 없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며, 편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일 시에 컴파일러가 자동적으로 추가해준다.
interface PlayingCard{
public static final int SPADE = 4;
final int DIAMONE = 3; // public static final int DIAMOND = 3;
static int HEAR = 2; // public static final int HEART = 2;
int CLOVEr = 1; // public static final; int CLOVER = 1;
public abstract String getCardNumber();
String getCardKind(); // public abstract String getCardKind();
}
인터페이스의 상속
인터페이스는 인터페이스로부터만 상속받을 수 있으며, 클래스와는 달리 다중 상속, 즉 여러 개의 인터페이스로부터 상속을 받는 것이 가능하다.
interface Movable {
/** 지정된 위치(x, y)로 이동하는 기능의 메서드 */
void move(int x, int y);
}
interface Attackable {
/** 지정된 대상(u)을 공격하는 기능의 메서드 */
void attack(Unit u);
}
interface Fightable extends Movable, Attackable {}
Fightable 자체에 정의된 멤버가 하나도 없지만 조상 인터페이스로부터 상속받은 두 개의 추상 메서드, move(int x, int y)와 attack(Unit u)을 멤버로 갖게 된다.
인터페이스의 구현
인터페이스도 자신에 정의된 추상 메서드의 몸통을 만들어주는 클래스를 작성해야 하는데, 그 방법은 추상 클래스가 자신을 상속받는 클래스를 정의하는 것과 동일하다.
다만 클래스는 확장한다는 의미의 키워드 ‘extends’를 사용하지만 인터페이스는 구현한다는 의미의 키워드 ‘implements’를 사용한다.
class 클래스이름 implements 인터페이스이름{
// 인터페이스에 정의된 추상메서드를 모두 구현해야 한다.
}
class Fighter implements Fightable{
public void move(int x, int y) { /* 내용 생략 */ }
public void attack(Unit u) { /* 내용 생략 */ }
}
상속과 구현을 동시에 할 수도 있다.
class Fighter extends Unit implements Fightable {
public void move(int x, int y) { /* 내용 생략 */ }
public void attack(Unit u) { /* 내용 생략 */ }
}
인터페이스를 이용한 다형성
인터페이스 타입의 참조 변수로 이를 구현한 클래스의 인스턴스를 참조할 수 있으며, 인터페이스 타입으로의 형변환도 가능하다.
Fightable f = (Fightable)new Fighter();
또는
Fightable f = new Fighter();
Fightable method() {
...
Fighter f = new Fighter();
return f;
// 이 두 문장을 한 문장으로 바꾸면 다음과 같다. return new Fighter();
}
리턴 타입이 인터페이스라는 것은 메서드가 해당 인터페이스를 구현한 클래스의 인스턴스를 반환한다는 것을 의미한다.
인터페이스의 장점
1. 개발 시간을 단축시킬 수 있다.
인터페이스가 작성되면, 이를 사용해서 프로그램을 작성하는 것이 가능하다. 메서드를 호출하는 쪽에서는 메서드의 내용에 관계없이 선언부만 알면 되기 때문이다.
그리고 동시에 다른 한쪽에서는 인터페이스를 구현하는 클래스를 작성하게 하면, 인터페이스를 구현하는 클래스가 작성될 때까지 기다리지 않고도 양쪽에서 동시에 개발을 진행할 수 있다.
2. 표준화가 가능하다.
프로젝트에 사용되는 기본 틀을 인터페이스로 작성한 다음, 개발자들에게 인터페이스를 구현하여 프로그램을 작성하도록 함으로써 보다 일관되고 정형화된 프로그램의 개발이 가능하다.
3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.
서로 상속관계에 있지도 않고, 같은 조상 클래스를 가지고 있지 않은 서로 아무런 관계도 없는 클래스들에게 하나의 인터페이스를 공통적으로 구현하도록 함으로써 관계를 맺어 줄 수 있다.
4. 독립적인 프로그래밍이 가능하다.
인터페이스를 이용하면 클래스의 선언과 구현을 분리시킬 수 있기 때문에 실제 구현에 독립적인 프로그램을 작성하는 것이 가능하다. 클래스와 클래스 간의 직접적인 관계를 인터페이스를 이용해서 간접적인 관계로 변경하면, 한 클래스의 변경이 관련된 다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능하다.
'Server > 자바의정석' 카테고리의 다른 글
[Java 입문] 오류 & 예외 (4) | 2022.09.29 |
---|---|
[Java 입문] 디폴트 메서드 & Static 메서드, 내부 클래스 (1) | 2022.09.29 |
[Java 입문] 다형성(polymorphism) (0) | 2022.09.28 |
[Java 입문] 제어자(modifier), 캡슐화 (0) | 2022.09.28 |
[Java 입문] Super (0) | 2022.09.28 |