추상 클래스, 추상 메서드
추상 클래스 (abstract class)
- 미완성 설계도, 미완성 메서드를 갖고 있는 클래스
추상클래스란, 미완성 설계도이다.
즉, 부족한 부분이 있다는 뜻이다.
부족하고, 미완성이라는 이야기가 멤버에 대한 이야기가 아니라,
미완성 메서드를 갖고 있으면, 미완성 설계도, 즉, 추상 클래스이다.
코드를 보자.
Player라는 클래스가 있다. 이클래스는 추상클래스다. (미완성 클래스)
그 이유는, 미완성 메서드를 가지고 있기 때문이다.
미완성 메서드는,추상 메서드라고 불린다.
몸통 블럭{}이 없는 메서드를 추상 메서드라고 부른다.
추상 메서드(미완성 메서드)를 가지고 있는 클래스를 추상 클래스(미완성 메서드)라고 부른다.
추상 메서드는 몸통{}이 없는 대신, 앞에다 abstract라고 붙인다.
원래는, 몸통이 없으면 메서드에서 에러가 나는데,
abstract를 붙여줌으로서, 추상 메서드임을 알려주면, 몸통이 없어도 에러가 나지 않는다.
그리고, 이 추상메서드를 가지고 있는 클래스 앞에도 abstract를 붙인다.
그러면 이 클래스를 딱 보면, "앞에 abstract가 붙었으니, 이 클래스 안에는 추상 메서드가 있겠구나!" 라고 알 수 있다.
- 다른 클래스 작성에 도움을 주기 위한 것. 인스턴스 생성 불가.
추상 클래스는 설계도가 미완성이다. 즉, 인스턴스 객체를 생성할 수 없다.
이렇게 추상 클래스의 인스턴스를 생성하면, 에러가 발생한다.
그렇다면, 인스턴스(객체)를 생성할 수 없는 클래스를 만드는 이유는 뭘까?
다른 클래스를 작성하는데 도움을 주기 위함이다.
- 상속을 통해 추상 메서드를 완성해야 인스턴스 생성가능
이런 식으로, 다른 클래스에서 추상클래스를 상속받아서,
추상클래스의 추상메서드의 몸통{}을 만들어서 추상메서드를 구현해주면, play와 stop()은 더이상 추상메서드가 아니다.
그래서 abstract도 붙이지 않는다.
그리고 AudioPlayer라는 클래스도 더 이상 추상메서드가 없으므로, 추상클래스가 아니다. 따라서 abstract도 붙이지 않는다.
상속받은 Player클래스는 추상클래스이지만,
AudioPlayer는 완성된 클래스이므로, 인스턴스를 생성할 수 있다.
Player타입의 변수에 담아도 된다. 조상타입이기 떄문이다.
Player클래스의 메서드는 어떻게 호출이 가능하냐면,
AudioPlayer클래스에서 상속받은 추상 메서드를 완성시켰기 떄문에,
player.play를 하면, 실제 구현된 AudioPlayer객체의 메서드가 호출된다. 추상메서드가 호출되는 것이 아니다.
추상 메서드 (abstract method)
- 미완성 메서드, 구현부(몸통 {})가 없는 메서드
추상 메서드는 미완성 메서드이다.
원래 메서드 = 선언부 + 구현부 로 되어있는데,
구현부가 없이 메서드 = 선언부 로 되어있는 메서드를 추상 메서드라고 한다.
이런 식으로, {}구현부가 없이 선언부;로 끝나고, 앞에 abstract를 붙이면, 추상메서드가 된다.
추상메서드를 사용하는 경우는 다음과 같다.
- 꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우
추상 메서드는, 클래스에 꼭 필요하지만 자손마다 다르게 구현될 것으로 예상되는 경우에 사용한다.
이때, 다르게 구현 이라는 뜻은, 몸통{}의 내용이 자손마다 다르게 다르게 구현된다는 뜻이다.
Player라는 추상클래스가 있다. 해당 클래스에는 추상메서드가 2개있다.
이 Player추상클래스를 조상으로 상속받아서 만든 AudioPlayer라는 클래스는 상속받은 추상메서드를 다 구현해 주었다.
즉, AudioPlayer는 완전한 클래스이다. abstract를 붙이지 않는다.
그런데, AbstractPlayer라는 클래스는, AudioPlayer와 마찬가지로 추상클래스 Player를 상속을 받았지만,
상속받은 2개의 추상 메서드 중에, 1개만 구현완료 했다.
그래서, AbstractPlayer클래스의 앞에는 abstract를 붙여줘야 한다.
왜냐하면, 상속받은 추상메서드 2개를 전부 구현완료해야 완성이 되는데, 1개만 구현했으므로 미완성클래스이다.
만약에 이런 경우, 클래스 앞에 abstract를 실수로 붙이지 않으면 에러가 발생한다.
그런데, 우리가 AbstractPlayer클래스만 보면, 추상메서드가 없는 것 처럼 보인다.
하지만 Player클래스를 상속받았기 때문에 상속받은 멤버를 잘 확인해야 한다. 이점을 주의하자.
어쨋든, 지금처럼, 추상클래스를 상속받았을 때,
추상 메서드를 다 구현해도 되고, 일부만 구현해도 된다.
다만 일부만 구현했을 땐 해당 클래스는 여전히 추상 클래스이다.
필요에 따라서 선택하면 된다.
- 추상 메서드 호출 가능 (호출할 때는 선언부만 필요)
Player라는 추상 클래스가 있다.
밑에는 추상메서드가 2개 있다. (play, stop)
이게 무슨 의미냐면, 어떤 Player들은 어떤 것을 play하거나 stop하는 기능이 있어야 한다는 뜻이다.
그런데, CD플레이어나, DVD플레이어는 플레이 방식이나, 멈추는 방식이 다를 것이다.
그래서 Player클래스에서 play메서드와 stop메서드를 작성을 해봐야 소용이 없다.
왜냐하면, 자손(player)마다 다르게 구현되야 하기 때문이다.
추상 메서드 말고, 그냥 빈 몸통을 만들어 줘도 되긴 하지만,
abstract를 붙이지 않고 아무것도 없다면, 이것을 상속받아서 사용하는 쪽에서는 이것이 구현되어있는 줄 알 수도 있다.
근데, abstract를 붙이면, "이건 구현되어 있지 않은 메서드이므로 내가 이것을 상속받으면 이 추상메서드를 구현해서 클래스를 완성해야 되는구나!"라고 강제시키는 효과가 있다.
그래서, 추상클래스가 뭐 대단히 어려운게 아니라,
일반 클래스와 똑같은데, 추상메서드를 가지고 있는 것 뿐이다.
코드 마지막 메서드를 보면, play라는 인스턴스 메서드가 있다.
인스턴스 메서드에서 추상메서드를 호출하고 있다.
"구현부가 없는데, 추상메서드를 어떻게 호출하나요? 에러나는 것 아닌가요?"
하지만, 가능하다.
지금은 몸통이 없지만, 나중에 상속을 통해서 자손이 완성할 수 있기 때문에 그때는 호출이 가능하다.
인스턴스 메서드는 객체 생성후에 호출할 수 있다.
따라서, 객체를 생성한다는 말은,
1. 상속을 통해 자손이 완성한 다음에,
2. 자손 객체 생성
3. DvdPlayer d = new DvdPlayer();
4. d.play();
그러면, 인스턴스 메서드인 play메서드에 매개변수에 있는 pos를 전달하며 추상메서드였던 play를 호출한다.
그러면, 추상메서드였던 play는 상속을 통해 자손이 구현을 해놓았고, 구현된 메서드가 호출된다.
이런 방식으로 추상메서드를 인스턴스 메서드를 통해 호출할 수 있다.
'JAVA' 카테고리의 다른 글
추상 클래스의 작성 (2) (0) | 2022.04.05 |
---|---|
추상 클래스의 작성 (1) (0) | 2022.04.05 |
여러 종류의 객체를 배열로 다루기 (0) | 2022.04.04 |
매개변수 다형성 (0) | 2022.04.04 |
instanceof 연산자 (0) | 2022.04.03 |
댓글
이 글 공유하기
다른 글
-
추상 클래스의 작성 (2)
추상 클래스의 작성 (2)
2022.04.05 -
추상 클래스의 작성 (1)
추상 클래스의 작성 (1)
2022.04.05 -
여러 종류의 객체를 배열로 다루기
여러 종류의 객체를 배열로 다루기
2022.04.04 -
매개변수 다형성
매개변수 다형성
2022.04.04