객체지향을 본격적으로 활용하기 위해, 추상(Abstract)와 인터페이스(interface)의 개념이 존재한다.

  • 자바에서는, 일종의 미완성 클래스라고 할 수 있는 추상(Abstract)클래스를 제공하는데, 추상클래스는 직접적으로 객체(인스턴스)를 생성할 수 없지만,
    < 새로운 클래스(추상클래스를 상속하는 자식 클래스) 를 작성하는데 밑바탕이 되는 역할을 해준다는 것>에 의미가 있다.
    예를 들어, 사각형/ 원/ 삼각형 이라는 클래스는 <공통적으로 넓이()와 모양()>이라는 메소드가 필요하다.
    그것을 반드시 구성할 수 있도록 추상 클래스에 설계해놓고 알려준다.
    - 규칙 : 추상클래스 꼭 상속받아야 하며, 모든 추상메소드는 자식클래스에서 구현이 되어야한다.


[1] 추상의 개념을 이용해서, 음악 플레이어 클래스를 구현해보자.

  1. Player클래스를 만들어보자. 그리고 접근제한자 public 대신 <abstract>로 바꿔서 추상클래스로 바꾸자.
  2. 안에 추상메소드를 넣어줘야한다. 인터페이스처럼 body{}가 없다.3가지 매소드를 넣어주자.
    abstract class Player {
       
         abstract void play(String songName);
         abstract void pause();
        abstract void stop();
  3. }


  4. 메인클래스를 만들고 추상클래스를 상속(extends Player)하자.
    *추상 클래스를 상속했다면, 그 안의 추상 메소드들은 모두 implements해야한다. 오류가 뜨는 것을클릭해서 메소드들을 구현하자.
      -> 오버라이딩 되면서, 추상클래스들의 추상 메소드들이 implements된다.


    @Override
     void play(String songName) {
         // TODO Auto-generated method stub
        
     }

    @Override
     void pause() {
         // TODO Auto-generated method stub
        
     }

    @Override
     void stop() {
         // TODO Auto-generated method stub
        
     }

4. 이제 비어있는, 추상 메소드들을  구현화하자.
     @Override
     void play(String songName) {
         System.out.println(songName+"곡을 재생합니다");       
     }

    @Override
     void pause() {
         System.out.println("곡을 일시정지 합니다");       
     }

    @Override
     void stop() {
         System.out.println("곡을 정지합니다");
     }

5. 메인메소드에서 구현화한 추상메소드들을 이용해보자. 이 때, 그냥 평소 호출하듯이 play("");를 호출하면, 오류가 뜬다. 그 이유는 메인메소드가 static이기 때문이다.
     클래스의 것으로, 클래스에서만 사용할 수 있도록 만든 static 메소드 내부에서는 반드시 호출되는 메소드들도 static이어야만 한다.*****
  ==> 이러한 것을 해결하는 방법으로, 호출하는 메소드에 static을 붙혀줄 수 도 있지만,
      ****< 메인클래스의 객체를 생성한 뒤, 객체.를 이용해서 호출하면 static이 붙은 메인메소드안에서 호출이 가능하다.>****

    public static void main(String[] args) {

        Main main = new Main();
         main.play("따르릉 by 홍진영");
        
     }

6. 다른 메소드 2개도 호출하여 실행해본다.


public class Main extends Player {

    public static void main(String[] args) {

        Main main = new Main();
         main.play("따르릉 by 홍진영");
        
         main.pause();
         main.stop();
        
     }

    @Override
     void play(String songName) {

        System.out.println(songName+"곡을 재생합니다");
        
     }

    @Override
     void pause() {

        System.out.println("곡을 일시정지 합니다");
        
     }

    @Override
     void stop() {

        System.out.println("곡을 정지합니다");

    }

}


[2] 추상의 개념을 이용해서 동물 클래스를 구현해보자.


1. Animal클래스를 만들고, 추상클래스로 바꾸자. 그리고  abstract void crying(); 메소드 하나를 넣어주자.

2. Dog클래스를 만들고 Animal 추상클래스를 상속하자. 추상메소드를 가져와서, 개가 우는 방식으로 구현화하자.

public class Dog extends Animal{

    @Override
     void crying() {
         System.out.println("월 ! 월 !");
     }

}

3. 마찬가지로 Cat 클래스를 만들고 추상클래스를 상속해서, 추상메소드를 구현화해주자.

4. 메인클래스에서, dog/cat객체를 만들어서, crying()을 호출해준다.
  - [1]에서는 메인클래스가 직접 추상클래스를 상속해서 이너메소드로 추상메소드가 오버라이딩 되었다. 하지만 이너메소드이면서 static메소드인 메인메소드에서 nonstatic 이너메소드를 호출 할 수없으니, 메인객체를 만들어서, 외부에서 호출하는 것처럼 만들었다.
    하지만, 이번에는 메인클래스에서 추상클래스를 상속한 것이 아니므로, 메인클래스의 객체를 생성할 필요가 없다.

    public static void main(String[] args) {

        Dog dog = new Dog();
         Cat cat = new Cat();
         dog.crying();
         cat.crying();
        
     }



[정리] 이렇게 추상클래스를 상속함으로써, 반드시 구현화해야하는 추상 메소드들을 알려준다. 사용자는 상속한 자식클래스에서 꼭 implements를 통해 오버라이딩해서 구현화해야하니 , 필요한 메소드들을 미리 알림을 받을 수 있고, 설계적인 측면에서 효율적으로 가져오면서, 안빠트리고 사용할 수 있다.

+ Recent posts