JAVA/JAVA 기초

Java 추상 클래스(Abstract Class)와 인터페이스(Interface) 이해하기

임베디드 친구 2024. 10. 2. 13:27
반응형

추상 클래스와 인터페이스는 객체 지향 프로그래밍의 중요한 개념 중 하나로, 코드의 재사용성과 유지보수성을 높이고, 상속을 통해 코드의 확장성을 지원합니다. 특히, 자바(Java)에서는 이 두 개념을 통해 상속과 구현의 설계를 명확하게 하고 다형성을 극대화할 수 있습니다. 이번 포스트에서는 추상 클래스와 인터페이스의 차이점과 활용 방법을 살펴보고, 코드 예제와 함께 이 개념들을 이해할 수 있도록 설명하겠습니다.

1. 추상 클래스(Abstract Class)란?

추상 클래스는 공통된 속성과 메서드를 정의해 두고, 상속받는 클래스에서 이를 구체화하여 사용할 수 있도록 하는 클래스입니다. 말 그대로 '추상적'인 형태의 클래스이며, 그 자체로는 인스턴스를 생성할 수 없습니다. 주로 코드의 중복을 방지하고, 계층 구조에서 공통된 기능을 묶어 두는 용도로 사용됩니다.

추상 클래스의 특징

  1. 인스턴스화할 수 없다: 추상 클래스는 new 키워드를 사용해 인스턴스를 생성할 수 없습니다. 예를 들어, Animal animal = new Animal();와 같은 코드는 오류를 발생시킵니다.
  2. 추상 메서드(Abstract Method)를 포함할 수 있다: 추상 메서드는 선언만 되어 있고, 구현은 하위 클래스에서 하도록 강제됩니다. 선언부에는 abstract 키워드가 붙습니다.
  3. 일반 메서드도 포함할 수 있다: 추상 메서드뿐만 아니라 구현된 일반 메서드도 포함될 수 있습니다. 하위 클래스에서 이러한 메서드를 그대로 사용할 수 있습니다.
  4. 생성자 및 필드를 가질 수 있다: 일반 클래스와 같이 필드와 생성자를 가질 수 있으므로, 하위 클래스에서 공통된 속성을 공유하고 초기화할 수 있습니다.
abstract class Animal {
    String name;

    // 추상 메서드: 하위 클래스가 반드시 구현해야 함
    abstract void bark();

    // 일반 메서드: 하위 클래스가 그대로 사용할 수 있음
    void displayName() {
        System.out.println("이 동물의 이름은 " + name + "입니다.");
    }
}
class Cat extends Animal {
    // 추상 메서드 구현
    void bark() {
        System.out.println("야옹");
    }
}
class Dog extends Animal {
    // 추상 메서드 구현
    void bark() {
        System.out.println("멍멍");
    }
}

위 코드에서 Animal 클래스는 추상 클래스로 선언되어 있으며, bark()라는 추상 메서드를 포함하고 있습니다. Cat과 Dog 클래스는 Animal 클래스를 상속받아 bark() 메서드를 구현하고 있습니다. 이를 통해 각 동물의 울음소리를 개별적으로 정의할 수 있게 됩니다.

추상 클래스의 활용

추상 클래스는 주로 다음과 같은 경우에 활용됩니다:

  • 공통 기능이나 속성을 묶어 코드 중복을 방지하고, 상속 계층 구조를 명확히 하고 싶을 때.
  • 하위 클래스가 반드시 구현해야 하는 메서드를 정의하고, 이를 강제하고자 할 때.
  • 추상 클래스에 정의된 공통된 메서드를 여러 하위 클래스가 그대로 사용하거나, 재정의하여 사용할 수 있도록 하고자 할 때.

추상 클래스는 공통된 로직을 구현하고, 하위 클래스가 개별적으로 필요한 메서드만 재정의함으로써 코드의 재사용성을 높이고, 일관성을 유지할 수 있습니다.

2. 인터페이스(Interface)란?

인터페이스는 클래스가 특정 메서드들을 반드시 구현하도록 강제하는 일종의 규약입니다. 인터페이스에는 메서드의 선언만 있으며, 구현체는 인터페이스를 구현하는 클래스에 따라 다르게 정의됩니다. 자바에서는 인터페이스를 통해 다중 상속을 구현할 수 있으며, 여러 클래스에 공통적인 메서드를 제공하여 일관성을 유지할 수 있습니다.

인터페이스의 특징

  1. 추상 메서드만 포함할 수 있다: 인터페이스에는 메서드의 선언만 포함되며, 구현은 없습니다. 따라서 모든 메서드는 기본적으로 abstract이고, 생략 가능합니다.
  2. 필드가 상수로 선언된다: 인터페이스 내에 정의된 필드는 static final로 선언된 상수로만 사용할 수 있습니다.
  3. 여러 인터페이스를 구현할 수 있다: 자바에서는 클래스가 하나의 클래스만 상속받을 수 있지만, 인터페이스는 여러 개를 동시에 구현할 수 있습니다. 이를 통해 다중 상속이 가능합니다.
  4. 인터페이스는 객체를 생성할 수 없다: 인터페이스는 추상 클래스와 마찬가지로 인스턴스를 생성할 수 없습니다. Fly fly = new Fly();와 같은 코드는 오류를 발생시킵니다.
// 인터페이스 선언
interface Fly {
    void fly(); // 추상 메서드, 구현은 인터페이스를 구현한 클래스가 수행함
}
class Butterfly implements Fly {
    // Fly 인터페이스의 추상 메서드 구현
    public void fly() {
        System.out.println("나비가 날아갑니다.");
    }
}
class Sparrow implements Fly {
    // Fly 인터페이스의 추상 메서드 구현
    public void fly() {
        System.out.println("참새가 날아갑니다.");
    }
}

위 코드에서 Fly 인터페이스는 fly()라는 메서드를 포함하고 있으며, Butterfly와 Sparrow 클래스가 이를 구현하고 있습니다. 각 클래스는 Fly 인터페이스의 fly() 메서드를 자신만의 방식으로 정의하고 있습니다.

인터페이스의 활용

인터페이스는 주로 다음과 같은 경우에 사용됩니다:

  • 클래스가 특정 메서드를 구현하도록 강제하고자 할 때.
  • 여러 클래스에 공통된 메서드를 정의하고, 일관된 코드 구조를 유지하고자 할 때.
  • 클래스가 여러 인터페이스를 구현하여 다양한 기능을 제공하고자 할 때.
  • 자바의 다형성(Polymorphism)을 극대화하고자 할 때. 예를 들어, 다양한 클래스 객체를 하나의 인터페이스 타입으로 처리할 수 있습니다.

3. 추상 클래스와 인터페이스의 차이점

추상 클래스와 인터페이스는 공통적으로 하위 클래스나 구현체가 특정 메서드를 구현하도록 강제한다는 점에서 유사하지만, 몇 가지 중요한 차이점이 있습니다.

구현 차이

  • 추상 클래스는 일반 메서드와 추상 메서드를 모두 포함할 수 있지만, 인터페이스는 오직 추상 메서드만을 포함할 수 있습니다.
  • 추상 클래스는 필드(속성)와 생성자를 가질 수 있지만, 인터페이스는 오직 static final로 선언된 상수만 가질 수 있습니다.사용 목적과 설계 원칙
  • 추상 클래스는 "is-a" 관계를 표현하고, 상속 계층에서 상위 클래스로 사용됩니다. 주로 객체들의 공통된 특성을 모아둔 상위 클래스로 사용됩니다.
  • 인터페이스는 "can-do" 관계를 표현하며, 여러 클래스가 동일한 동작을 구현하도록 강제합니다. 예를 들어, Fly 인터페이스는 Butterfly, Bird, Airplane 같은 클래스에서 구현될 수 있습니다.

4. 추상 클래스와 인터페이스의 활용 사례

1. 추상 클래스 사용 예시:

  • 동물, 차량과 같은 공통된 속성과 메서드를 가지며, 특정 기능을 반드시 구현해야 하는 경우.
  • 공통된 로직을 제공하고, 하위 클래스에서 추가 구현을 강제하고자 할 때.

2. 인터페이스 사용 예시:

  • Comparable, Serializable 같은 인터페이스는 자바에서 이미 사용되는 대표적인 예입니다. 이를 통해 클래스가 특정 기능을 수행할 수 있도록 강제하고, 다형성을 제공합니다.
  • 여러 클래스가 동일한 메서드를 구현하여 동일한 타입으로 다룰 수 있도록 할 때 사용됩니다.

5. 결론

추상 클래스와 인터페이스는 자바에서 코드의 재사용성과 확장성을 높이는 데 중요한 역할을 합니다. 추상 클래스는 공통된 속성과 메서드를 제공하고, 하위 클래스가 이를 재정의하거나 그대로 사용할 수 있도록 하며, 인터페이스는 특정 메서드를 구현하도록 강제하여 코드의 일관성을 유지하고, 다형성을 극대화합니다. 두 개념을 적절히 사용하면, 견고하고 유지보수하기 쉬운 객체 지향 프로그램을 작성할 수 있습니다.

반응형