자바/객체지향 프로그래밍(OOP)

추상 클래스

Blue_bull 2025. 1. 23. 01:00

abstract는 Java에서 추상화(Abstraction)를 구현하는 데 사용되는 키워드로, 클래스 또는 메서드에 적용됩니다. 이를 통해 코드의 공통적인 구조를 정의하고, 세부적인 구현은 하위 클래스에서 처리하도록 강제할 수 있습니다. 아래에서 추상 클래스, 추상 메서드, 그리고 추상 변수에 대해 자세히 설명하겠습니다.


1. 추상 클래스 (Abstract Class)

1.1. 정의

  • 추상 클래스는 abstract 키워드로 선언된 클래스입니다.
  • 직접 객체를 생성할 수 없으며, 상속을 통해 자식 클래스가 이를 구현해야 합니다.
  • 공통된 동작구체적인 동작을 함께 정의할 수 있습니다.
  • 추상 클래스는 추상 메서드뿐만 아니라 일반 메서드도 포함할 수 있습니다.

1.2. 특징

  1. 인스턴스화 불가: 추상 클래스는 직접 객체를 생성할 수 없고, 반드시 자식 클래스를 통해 사용해야 합니다.

    abstract class Animal {}
    Animal obj = new Animal(); // 컴파일 에러
  2. 상속을 통해 사용: 추상 클래스는 자식 클래스에서 상속받아 구체적인 동작을 정의합니다.

  3. 구현의 강제성: 추상 클래스에 포함된 추상 메서드는 자식 클래스에서 반드시 구현해야 합니다.

  4. 멤버 구성:

    • 추상 메서드구현된 메서드를 모두 포함할 수 있음.
    • 인스턴스 변수, static 변수, 생성자 등을 포함 가능.

1.3. 예시

abstract class Animal {
    String name; // 인스턴스 변수

    Animal(String name) { // 생성자
        this.name = name;
    }

    void sleep() { // 일반 메서드
        System.out.println(name + " is sleeping.");
    }

    abstract void sound(); // 추상 메서드
}

class Dog extends Animal {
    Dog(String name) {
        super(name);
    }

    @Override
    void sound() {
        System.out.println("Bark!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("Buddy");
        dog.sleep(); // 출력: Buddy is sleeping.
        dog.sound(); // 출력: Bark!
    }
}

분석

  • Animal 클래스는 추상 클래스이며, 직접 객체를 생성할 수 없음.
  • sound 메서드는 추상 메서드로, 자식 클래스인 Dog에서 반드시 구현.
  • 공통 동작(sleep)은 추상 클래스에 정의하여 코드 중복을 줄임.

2. 추상 메서드 (Abstract Method)

2.1. 정의

  • 추상 메서드는 메서드의 선언부만 존재하고, 구현부가 없는 메서드입니다.
  • abstract 키워드를 사용하여 선언하며, 구현은 자식 클래스에서 이루어집니다.
  • 추상 메서드는 반드시 추상 클래스 또는 인터페이스에 포함되어야 합니다.

2.2. 특징

  1. 구현 강제: 추상 메서드는 자식 클래스에서 반드시 재정의(오버라이딩)해야 합니다.
  2. 메서드 시그니처만 정의: 동작의 공통된 인터페이스를 제공하며, 세부 구현은 자식 클래스에 맡김.
  3. 추상 클래스 내에서만 선언 가능:
    • 추상 메서드는 추상 클래스가 아닌 일반 클래스에 선언할 수 없습니다.

2.3. 예시

abstract class Shape {
    abstract void draw(); // 추상 메서드
}

class Circle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a circle");
    }
}

class Rectangle extends Shape {
    @Override
    void draw() {
        System.out.println("Drawing a rectangle");
    }
}

public class Main {
    public static void main(String[] args) {
        Shape shape1 = new Circle();
        Shape shape2 = new Rectangle();

        shape1.draw(); // 출력: Drawing a circle
        shape2.draw(); // 출력: Drawing a rectangle
    }
}

분석

  • draw 메서드는 추상 메서드로, Shape 클래스에서는 구현되지 않았지만, 자식 클래스에서 각각의 형태에 맞게 구현.

3. 추상 변수 (Abstract Variable)

3.1. 개념

  • Java에서는 추상 변수라는 개념은 존재하지 않음. 대신 추상 클래스나 인터페이스에서는 상수(static final)를 정의하거나, 인스턴스 변수를 정의하여 자식 클래스에서 사용.
  • 인터페이스에서는 모든 변수가 public static final로 선언됨.

3.2. 추상 클래스에서 변수 사용

  • 추상 클래스에서는 일반 클래스처럼 인스턴스 변수, static 변수를 선언 가능.
abstract class Animal {
    String name; // 인스턴스 변수
    static int count = 0; // static 변수
}

3.3. 인터페이스에서 변수 사용

  • 인터페이스의 변수는 암묵적으로 public static final로 선언되며, 값을 반드시 초기화해야 함.
interface Constants {
    int MAX_VALUE = 100; // public static final
}

public class Main {
    public static void main(String[] args) {
        System.out.println(Constants.MAX_VALUE); // 출력: 100
    }
}

4. 추상 클래스와 인터페이스 비교

특징 추상 클래스 인터페이스
키워드 abstract interface
객체 생성 불가능 불가능
메서드 추상 메서드와 일반 메서드 포함 가능 모든 메서드는 추상 메서드 (Java 8 이후 default/static 가능)
변수 일반 변수, static 변수 포함 가능 public static final 상수만 포함
다중 상속 불가능 (단일 상속만 가능) 가능
사용 목적 공통 코드와 세부 구현을 일부 제공 구현 강제, 다형성을 위한 공통 인터페이스 제공

5. 추상 클래스의 활용

  1. 템플릿 메서드 패턴:
    • 알고리즘의 공통적인 뼈대를 정의하고, 세부적인 구현은 자식 클래스에서 오버라이딩.
  2. 코드 재사용:
    • 공통 동작은 추상 클래스에 정의하고, 중복을 줄임.
  3. 확장 가능성:
    • 새로운 기능 추가 시 추상 클래스만 수정하면 되므로 유지보수가 용이.

6. 결론

  • 추상 클래스는 공통적인 동작과 구조를 정의하고, 구체적인 구현은 자식 클래스에서 하도록 강제하는 도구.
  • 추상 메서드는 구현 강제를 통해 다형성을 실현하며, 메서드의 구조를 고정.
  • 추상 변수는 직접적인 개념으로 존재하지 않지만, 추상 클래스와 인터페이스에서 각기 다른 방식으로 변수 정의 가능.
    추상화를 통해 코드의 확장성, 유지보수성, 재사용성을 크게 향상시킬 수 있습니다.

추상과 상속의 상관관계

추상(Abstraction)상속(Inheritance)은 객체 지향 프로그래밍(OOP)에서 서로 밀접하게 연관된 개념입니다.
이 두 개념의 상관관계를 이해하기 위해 각각의 본질과 역할을 살펴보고, 구체적인 연관성을 설명합니다.


1. 추상(Abstraction)의 개념

정의

  • 추상화는 객체의 복잡성을 줄이고, 핵심적인 정보만 표현하는 것을 의미합니다.
  • 추상화는 구체적인 구현은 감추고, 필요한 인터페이스(기능)를 정의하는 데 초점을 맞춥니다.
  • Java에서는 추상 클래스(abstract class)인터페이스(interface)를 통해 구현됩니다.

목적

  • 공통적인 동작(메서드)을 정의하고, 구체적인 구현은 자식 클래스에 맡김.
  • 코드를 재사용 가능하고, 유지보수성을 높이며, 다형성을 지원.

2. 상속(Inheritance)의 개념

정의

  • 상속은 한 클래스가 다른 클래스의 속성과 메서드를 물려받는 것을 의미합니다.
  • 부모 클래스(슈퍼 클래스)의 모든 멤버(변수와 메서드)를 자식 클래스(서브 클래스)가 상속받아 사용하거나, 확장(override)하여 새로운 기능을 추가할 수 있습니다.

목적

  • 코드의 재사용성을 높이고, 클래스 간 계층 구조를 형성.
  • 상위 클래스에서 공통 기능을 정의하고, 하위 클래스에서 구체적으로 구현.

3. 추상과 상속의 상관관계

추상과 상속은 다형성(Polymorphism)코드 재사용성을 중심으로 강하게 연결되어 있습니다.

3.1. 추상화는 상속을 전제로 설계됨

  • 추상 클래스는 상속을 통해 사용됩니다.
    • 추상 클래스는 객체를 직접 생성할 수 없으며, 자식 클래스가 이를 상속받아 구체적으로 구현해야 의미가 있습니다.
    • 예: abstract 키워드를 사용한 메서드는 자식 클래스에서 반드시 구현(override)되어야 함.

예시

abstract class Animal {
    abstract void sound(); // 추상 메서드: 구현 없음
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Bark");
    }
}

class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("Meow");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog(); // 상속을 통해 추상 클래스 사용
        Animal cat = new Cat();

        dog.sound(); // 출력: Bark
        cat.sound(); // 출력: Meow
    }
}
  • 분석:
    • Animal은 추상 클래스이며, 객체 생성 불가.
    • DogCat은 상속을 통해 추상 메서드를 구현하여 구체화.

3.2. 추상화는 상속의 구체적인 활용 사례

  • 상속은 코드 재사용에 초점이 맞춰져 있지만, 추상화를 통해 상속을 더욱 체계적으로 활용할 수 있습니다.
  • 부모 클래스에서 공통 동작의 인터페이스(구조)를 정의하고, 자식 클래스에서 구체적으로 구현함으로써 일관성확장성을 제공.

상속만 사용한 경우

class Animal {
    void sound() {
        System.out.println("Generic Animal Sound");
    }
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Bark");
    }
}
  • 여기서는 부모 클래스에서 sound의 동작이 이미 구현되어 있어, 자식 클래스에서 오버라이딩하지 않아도 동작 가능.
  • 반면, 추상 클래스를 사용하면 sound를 구현하지 않는 클래스는 컴파일 에러가 발생하므로, 모든 자식 클래스가 해당 메서드를 반드시 정의하도록 강제.

추상화로 구현 강제

abstract class Animal {
    abstract void sound(); // 추상화로 모든 자식 클래스에 구현 강제
}

class Dog extends Animal {
    @Override
    void sound() {
        System.out.println("Bark");
    }
}

class Cat extends Animal {
    @Override
    void sound() {
        System.out.println("Meow");
    }
}
  • 추상화는 설계상 구현 강제성을 통해 자식 클래스에서 일관된 인터페이스를 제공하게 만듦.

3.3. 추상화와 상속의 목적

추상화 상속
공통된 기능의 인터페이스(구조)를 정의 부모 클래스의 기능을 재사용하고 확장
구현 강제 → 코드의 일관성 확보 코드의 중복 제거 → 유지보수성 향상
객체의 구체적인 동작은 숨기고 필요한 것만 제공 상위 클래스의 동작을 재정의(Override) 가능

4. 추상화와 상속의 동시 사용 사례

템플릿 메서드 패턴

  • 추상 클래스에서 알고리즘의 뼈대(템플릿)를 정의하고, 일부 세부 구현은 자식 클래스에서 정의하도록 강제.
  • 부모 클래스는 공통 동작을 정의하고, 자식 클래스는 특정 동작만 변경 가능.

예시

abstract class Game {
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();

    // 템플릿 메서드
    public final void play() {
        initialize();
        startPlay();
        endPlay();
    }
}

class Football extends Game {
    @Override
    void initialize() {
        System.out.println("Football Game Initialized!");
    }

    @Override
    void startPlay() {
        System.out.println("Football Game Started!");
    }

    @Override
    void endPlay() {
        System.out.println("Football Game Ended!");
    }
}

public class Main {
    public static void main(String[] args) {
        Game game = new Football();
        game.play();
    }
}

분석

  1. 추상 클래스 Game은 템플릿 메서드(play)를 정의.
  2. 자식 클래스 Football은 추상 메서드를 구현하여 구체적인 동작 정의.
  3. play 메서드는 부모 클래스에서 공통된 알고리즘을 제공하므로, 자식 클래스의 구현과 상관없이 호출 가능.

5. 결론

  1. 추상화와 상속의 관계:
    • 추상 클래스는 상속을 전제로 설계되며, 상속을 통해 추상 메서드와 공통 동작을 구현하고 확장.
    • 상속만 사용하면 코드 재사용은 가능하지만, 추상화를 통해 구현 강제성일관성을 추가로 확보 가능.
  2. 상호 보완적 역할:
    • 추상화는 설계를 체계적으로 만들고, 상속이 이를 구체화함.
    • 두 개념은 다형성(Polymorphism)의 기반을 제공하여 객체 지향 설계의 핵심이 됨.
  3. 결론적 활용:
    • 추상화를 통해 상속 관계를 더욱 구조화하고, 유지보수성과 확장성을 강화.
    • 적절히 활용하면 코드 재사용성, 유연성, 일관성을 모두 확보할 수 있음.