Java/객체 지향

추상 클래스와 추상 메소드

늦은산책 2023. 5. 11. 00:02

추상 클래스(abstract class)

  • 미완성 설계도, 미완성 메소드를 갖고 있는 클래스
abstract class Player {
    abstract void play(int pos);
    abstract void stop();
}
추상 메소드가 클래스내에 존재한다면 그것은 추상 클래스이다. 그리고 abstract를 붙여주어야한다.
  • 다른 클래스 작성에 도움을 주기 위한것. 인스턴스 생성 불가
Player p = new Player();    //에러
이것은 추상 클래스이기 때문에 인스턴스를 생성할 수 없다
  • 그래서 상속을 통해 추상 메소드를 완성시켜야 인스턴스 생성이 가능하다
class AudioPlayer extends Player {
    void play(int pos) { // ... }
    void stop() { // ... }
}
현재 완성된 설계도 AudioPlayer에 추상적인 Player클래스를 상속시키고 안에있는 추상 메소드를 완성시켰다.

그러면
AudioPlayer ap = new AudioPlayer(); 가 가능한것이다. 그럼 여기서 질문

Player ap = new AudioPlayer(); 가 가능할까??
가능하다 왜냐하면 결정적으로 참조하고 있는 객체 AudioPlayer는 완성된 객체이기 때문이다.

 

추상 클래스의 작성

  • 여러 클래스에 공통적으로 사용될 수 있는 추상클래스를 바로 작성하거나 기존 클래스의 공통 부분을 뽑아서 추상클래스를 만든다.
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() { //현재 위치에 정지 }
}
그리고 Unit을 상속시켜 move의 구현화부분을 작성해서 완성시킨다.

여기서 다형성의 2번째 장점(여러배열에 한번에 값넣기)까지 적용시킨다면

Unit[] group = new Unit[3];
group[0] = new Marine();
group[1] = new Tank();
group[2] = new Dropship();

for(int i = 0; i< group.length; i++) {
    group[i].move(100, 200);
}
으로 하여 모든 클래스에 move값을 한번에 넣어줄수 있다.
  • 추상화 ↔ 구체화
    • 추상화된 코드는 구체화된 코드보다 유연하다. 변경에 유리하다는 것이다. 이것은 굉장히 큰 장점이다.
      이것은 후에 코드를 작성할때 크게 느낄수 있다.

 

추상 메소드(abstract method)

  • 미완성 메소드, 구현부(몸통 {})가 없는 메소드
추상 메소드 작성 방법
abstract 리턴타입 메소드이름();
  • 꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우
abstract class Player {
    abstract void play(int pos);
    abstract void stop();
}
추상 클래스 안에 2개의 추상메소드가 들어있다

class AudioPlayer extends Player {
    void play(int pos) { // 내용 생략 }
    void stop() { // 내용 생략 }
}
추상 클래스인 Player를 상속받아 추상 메소드를 구현했다

abstract class AbstractPlayer extends Player {
    void play(int pos) { // 내용 생략 }
}
추상 클래스인 Player를 상속받았는데 2개의 추상메소드에서 한개만 구현했다면 여전히 추상메소드가 존재한다
아까 말했지만 클래스 안에 있는 메소드중 하나라도 추상 메소드가 있다면 그건 abstract 클래스가 되어야한다.
  • 조금 신기하겠지만 추상 메소드는 호출이 가능하다(호출할때는 선언부만 필요하기 때문이다.)
abstract class Player {
    boolean pause;
    int currentPos;
    
    Player() {               // 추상 클래스도 생성자를 만들어줘야 한다.
        pause = false;
        currentPos = 0;
    }
    
    abstract void play(int pos);
    abstract void stop();
    
    void play() {
        play(currentPos);    // 추상 메소드를 사용하는 부분이다.
    }
}
하지만 보이는것처럼 play()의 메소드가 완성되지 않았기때문에 상속을 통해 메소드가 완성되면
그때 객체 생성을 하여 play()가 호출되고 상속을 통해 완성된 메소드 내용이 구현될것이다.