[DEV] study&learn
article thumbnail

추상 클래스(abstract class)

미완성 설계도, 미완성 메소드를 가지고 있는 클래스
  • 객체를 직접 생성할 수 있는 클래스를 실체 클래스라고 한다면,
  • 이 클래스들의 공통적인 특성을 추출해서 선언한 클래스를 추상 클래스라고 한다.
  • 추상 클래스는 추상 메서드를 가질수 있다. (추상 메서드만 X)
    •  추상 클래스는 추상 메소드를 최소한 하나라도 가져야 할까?
      NOPE.
      추상 클래스는 추상 메소드를 가지지 않아도 상관없다.
      단, 추상 메소드를 하나라도 가지는 클래스는 추상 클래스가 되어야 한다.
  • 추상 클래스와 실체 클래스는 상속의 관계를 가지고 있다.
  • 추상 클래스가 부모, 실체 클래스가 자식으로 구현되어 실체 클래스는 추상 클래스의 모든 특성을 물려받고,
    추가적인 특성(필드, 메소드)을 가질 수 있다.
abstract class Player { // 추상 클래스(미완성 클래스)
	abstract void play(int pos); // 추상 메서드
    abstract void stop(); // 추상 메서드
}

위 코드를 보면 메서드 앞에 abstract 제어자를 붙여줌으로서

추상 메서드임을 명시한다.

 

void play(int pos);

와 같이 abstract 제어자를 사용하지 않고 미완성 메서드를 실행시키면, 컴파일 에러가 뜬다!

 

abstract class Player { // 추상 클래스
	// 추상 메서드
    abstract void play(pos);
}

또한 추상 메서드를 가지고 있는 클래스는

abstract 제어자를 사용하여 선언함으로서 추상 메서드를 가지고 있는 클래스임을 명시해야한다.

(만약 abstract 제어자를 사용하지 않으면,

추상메서드, 즉 몸통이 없는 메서드가 존재하는 클래스인지 아닌지를 알 수가 없다.)

 

인스턴스 생성 불가.

다른 클래스의 작성에 도움을 주기 위한 것. 따라서 인스턴스 생성이 불가하다.

Player p = new Player // 에러, 추상 클래스의 인스턴스 생성 불가

즉, 미완성 설계도로는 제품 생산이 불가하다는 뜻이다.

 

추상 클래스 상속.

상속을 통해 추상 메서드를 완성해야 인스턴스 생성이 가능하다.

class AudioPlayer extends Player {
	void play(int pos) { // 내용 } // 추상 메서드 구현
    void stop() { // 내용 } // 추상 메서드 구현
}

👇🏻

AudioPlayer ap = new AudioPlayer(); // OK!
// or
Player ap = new AudioPlayer(); // OK!
// AudioPlayer(부모) 클래스는 Player(자식) 클래스를 상속받았기 때문에
// 위와 같은 코드 작성도 가능하다.
// 다형성

 

추상 클래스의 용도

  • 공통된 필드와 메소드의 이름을 통일할 목적
    • 실체 클래스를 설계하는 사람이 여러 사람일 경우,실체 클래스마다 필드와 메서드가 제각기 다른 이름을 가질 수 있다.
    • 누군가는 소유자의 이름을 저장하는 필드를 "owner"로 다른 누군가는 "user"라고 할 수 있다.
    • 위와 같이 데이터와 기능이 모두 동일함에도 불구하고 이름이 다를때, 필드와 메소드 이름을 통일할 수 있다.
  • 실체 클래스를 작성할 때 시간 절약
    • 공통적인 필드와 메소드는 추상 클래스에 모두 선언해두고,
    • 다른 점만 실체 클래스에 선언하면 실체 클래스를 작성하는 데 시간을 절약할 수 있다.
    • 추상 클래스를 상속 받는 하위 클래스에서는 공통적인 필드와 메소드는 추상 클래스로부터 상속 받고,
    • 추가적인 특성만 각각 선언하면 된다.

일반적으로 개발 프로젝트에서 설계자와 코더는 다른 일을 수행한다.

설계자는 코더에게 클래스는 어떤 구조로 작성해야 한다는 것을 알려주어야 하는데,

이를 단순 문서로 전달하게 되면, 코더가 실수로 필드와 메소드 이름을 다르게 코딩할 수 있다.

코더가 작성해야 할 클래스가 다수이고 이 클래스들이 동일한 필드와 메소드를 가져야 할 경우,

설계자는 이 내용들을 추려내어 추상 클래스로 설계 규격을 만드는 것이 좋다.

 

 

추상 메소드와 재정의

추상 클래스는 실체 클래스가 공통적으로 가져야 할 필드와 메소드들을 정의해놓은 추상적인 클래스로,

실체 클래스의 멤버(필드, 메소드)를 통일하는데 목적이 있다.

모든 실체들이 가지고 있는 메소드의 실행 내용이 동일하다면 추상 클래스에 메소드를 작성하는 것이 좋다.

 

하지만 메소드의 선언만 통일하고, 실행 내용은 클래스마다 달라야 하는 경우가 있는데,

이런 경우를 위해서 추상 클래스는 추상 메소드를 선언할 수 있다.

추상 메소드는 abstract 키워드와 함께 메소드의 선언부만 있고 메소드 실행 내용인 중괄호 { } 가 없는 메소드를 말한다.

protected abstract 리턴타입 메소드이름(매개변수);
public abstract 리턴타입 메소드이름(매개변수);

 

추상 클래스 설계 시 하위 클래스가 반드시 실행 내용을 채우도록 강제하고 싶은 메소드가 있을 경우

해당 메소드를 추상 메소드로 선언한다.

자식 클래스는 반드시 추상 메소드를 재정의해서 실행 내용을 작성해야 한다.

 

 

위의 사진을 코드로 살펴보면 아래와 같다.

다음의 Dog 클래스는 추상 클래스은 Animal을 상속하고, 추상 메소드인 sound()를 재정의 하였다.

public abstract class Animal { // 추상 클래스
	public String kind;
    
    public void breath() {
    	System.out.println("숨을 쉽니다.");
    }
    
    public abstract void sound(); // 추상 메소드
}

👇🏻

public class Dog extends Animal {
	public Dog() {
    	this.kind = "포유류";
    }
    
    @Override // 추상 메소드 재정의
    public void sound() {
    	System.out.println("멍멍");
    }
}

 

추상 메소드의 호출

  • 가장 일반적인 방식으로 Dog 변수로 호출
  • Animal 변수로 타입 변환해서 sound() 메소드를 호출 (자동 타입 변환 및 재정의된 메소드 호출)
  • 부모 타입의 매개 변수에 자식 객체를 대입해서 메소드의 다형성을 적용
profile

[DEV] study&learn

@devjuni

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!