본문 바로가기
이직&취업/Java 기초 상식

추상 클래스(Abstract Class)와 인터페이스(Interface)를 알아보자!!

by journeylabs 2025. 3. 27.
728x90
반응형

목차

    추상 클래스와 인터페이스의 개념과 차이점

    객체 지향 프로그래밍(Object-Oriented Programming, OOP)에서는 코드의 구조를 명확히 하고 유지보수를 용이하게 하기 위해 **추상 클래스(Abstract Class)와 인터페이스(Interface)**를 활용합니다.
    이 두 개념은 공통적으로 **추상화(Abstraction)**를 구현하는 데 사용되지만, 그 목적과 사용 방식에는 차이가 있습니다. 본 글에서는 각각의 개념과 차이점을 상세히 살펴보도록 하겠습니다.


    1. 추상 클래스와 인터페이스의 개념 및 특징

    1.1 추상 클래스(Abstract Class)란?

    추상 클래스란 일부 메서드는 구현하고, 일부는 추상 메서드로 남겨두는 클래스를 의미합니다.
    즉, 완전히 구현되지 않은 클래스로, 이를 상속받은 하위 클래스에서 반드시 추상 메서드를 구현해야 합니다.

     

    주요 특징

    • 인스턴스화 불가능: 추상 클래스는 직접 객체를 생성할 수 없습니다.
    • 상속: 추상 클래스를 상속받는 자식 클래스는 추상 메서드를 반드시 구현해야 합니다. (구현하지 않으면 자식 클래스도 추상 클래스가 됩니다.)
    • 구현: 추상 메서드 외에 일반 메서드(구현이 있는 메서드)와 속성(멤버 변수)을 가질 수 있습니다.
    • 역할: 공통적인 속성과 메서드를 정의하고, 자식 클래스가 반드시 구현해야 하는 메서드를 지정하여 일관성을 유지합니다.

    종류

    • 순수 추상 클래스 (Pure Abstract Class) →  모든 메서드가 추상 메서드로만 구성된 클래스입니다. 인터페이스와 유사하게 동작하지만, 속성을 가질 수 있다는 차이점이 있습니다.
    • 일반 추상 클래스 (General Abstract Class) →  하나 이상의 추상 메서드와 일반 메서드를 모두 포함하는 클래스입니다.

    1.2 인터페이스(Interface)란?

    인터페이스는 클래스가 구현해야 할 "규칙"을 정의하는 역할을 수행합니다.
    이는 클래스 간 공통된 기능을 강제할 때 사용되며, 모든 메서드는 기본적으로 추상 메서드로 선언됩니다.

     

    주요 특징

    • 다중 상속: 클래스는 여러 개의 인터페이스를 구현(implements)할 수 있습니다. (다중 상속 지원)
    • 구현: 인터페이스를 구현하는 클래스는 인터페이스의 모든 추상 메서드를 반드시 구현해야 합니다.
    • 역할: 클래스가 제공해야 하는 기능을 명시적으로 정의하고, 클래스 간의 계약(contract) 역할을 수행합니다.
    • Java 8 이후:
      • Default 메서드: 인터페이스에 기본 구현을 제공하는 메서드입니다. 인터페이스를 구현하는 클래스에서 필요에 따라 재정의(override)할 수 있습니다.
      • Static 메서드: 인터페이스에 static 메서드를 정의할 수 있습니다. 이는 인터페이스 자체에 유틸리티 기능을 제공하는 데 유용합니다.

    종류

    • 일반 인터페이스 → 모든 메서드가 추상 메서드
    • 기능이 포함된 인터페이스 → default 메서드를 포함하는 경우 (Java 8 이후 지원)
    • 마커 인터페이스 (Marker Interface) → 아무런 메서드도 가지지 않는 인터페이스입니다. 특정 클래스에 특별한 속성이나 기능을 부여하는 데 사용됩니다. (예: Serializable, Cloneable)
    • 함수형 인터페이스 (Functional Interface) → 단 하나의 추상 메서드만 가지는 인터페이스입니다. 람다 표현식(lambda expression)을 사용하여 간결하게 구현할 수 있습니다. (예: Runnable, ActionListener)

    2. 추상 클래스와 인터페이스의 예제 코드

    2.1 추상 클래스 예제

    // 추상 클래스 선언
    abstract class Animal {
        String name;
    
        // 생성자
        Animal(String name) {
            this.name = name;
        }
    
        // 추상 메서드 (구현 없음)
        abstract void makeSound();
    
        // 일반 메서드 (구현 있음)
        void sleep() {
            System.out.println(name + " is sleeping.");
        }
    }
    
    // 추상 클래스를 상속받는 구체적인 클래스
    class Dog extends Animal {
        Dog(String name) {
            super(name);
        }
    
        @Override
        void makeSound() {
            System.out.println(name + " says: Woof! Woof!");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Dog dog = new Dog("Buddy");
            dog.makeSound(); // Buddy says: Woof! Woof!
            dog.sleep(); // Buddy is sleeping.
        }
    }

    🔍 설명:

    • Animal은 추상 클래스이며, makeSound() 메서드는 추상 메서드로 선언되었습니다.
    • Dog 클래스는 Animal을 상속받아 추상 메서드를 구현해야 합니다.
    • sleep() 메서드는 일반 메서드이므로, Dog에서 재정의하지 않아도 사용 가능합니다.

    2.2 인터페이스 예제

    // 인터페이스 선언
    interface Vehicle {
        void start();
        void stop();
    }
    
    // 인터페이스 구현 (implements)
    class Car implements Vehicle {
        @Override
        public void start() {
            System.out.println("Car is starting.");
        }
    
        @Override
        public void stop() {
            System.out.println("Car is stopping.");
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Car car = new Car();
            car.start(); // Car is starting.
            car.stop(); // Car is stopping.
        }
    }

    🔍 설명:

    • Vehicle은 인터페이스이며, start()와 stop() 메서드는 자동으로 abstract로 선언됩니다.
    • Car 클래스는 Vehicle을 **구현(implements)**해야 하며, 모든 메서드를 오버라이딩해야 합니다.

    2.3 Default 메서드 예시(Java 8 이후)

    interface MyInterface {
        void myMethod();
    
        default void defaultMethod() {
            System.out.println("MyInterface의 기본 구현");
        }
    }
    
    class MyClass implements MyInterface {
        @Override
        public void myMethod() {
            System.out.println("MyClass의 myMethod 구현");
        }
    
        // defaultMethod를 재정의할 수 있음 (선택 사항)
        @Override
        public void defaultMethod() {
            System.out.println("MyClass에서 재정의된 defaultMethod");
        }
    }
    
    public class DefaultMethodExample {
        public static void main(String[] args) {
            MyClass myObject = new MyClass();
            myObject.myMethod();
            myObject.defaultMethod(); // MyClass에서 재정의된 defaultMethod 출력
        }
    }

    🔍 설명:

     

    • MyInterface 인터페이스는 myMethod() 추상 메서드와 defaultMethod() 기본 메서드를 가지고 있습니다.
    • MyClass MyInterface를 구현하고 myMethod()를 구현합니다.
    • MyClass defaultMethod()를 재정의하여 자신만의 구현을 제공할 수 있습니다.
    • Default 메서드는 인터페이스에 새로운 기능을 추가하면서 기존 구현 클래스를 변경하지 않아도 되도록 해줍니다.

     

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

    비교 항목 추상 클래스 인터페이스
    선언 키워드 abstract class interface
    메서드 일반 메서드 + 추상 메서드 가능 모든 메서드가 기본 abstract (Java 8 이후 default 메서드 포함 가능)
    다중 상속 불가능 (extends 1개만 허용) 가능 (implements 여러 개 가능)
    생성자 가능 불가능
    필드(변수) 인스턴스 변수 사용 가능 public static final 상수만 선언 가능

    4. 주의사항

    4.1 추상 클래스 사용 시 주의할 점

    추상 클래스는 직접 객체를 생성할 수 없습니다.

    Animal a = new Animal(); // 오류 발생 (추상 클래스는 직접 인스턴스를 생성할 수 없음)

     

    모든 하위 클래스는 추상 메서드를 반드시 구현해야 합니다.

    class Cat extends Animal {
        // makeSound() 메서드를 구현하지 않으면 오류 발생!
    }

     

    생성자를 가질 수 있습니다.


    4.2 인터페이스 사용 시 주의할 점

    인터페이스의 모든 메서드는 기본적으로 public abstract입니다.

    interface Test {
        void method(); // public abstract가 자동 추가됨
    }

     

    자바 8 이후 default 및 static 메서드 추가 가능

    interface Test {
        default void show() {
            System.out.println("Default method");
        }
    }

     

    다중 인터페이스 구현 시, 중복된 메서드가 있을 경우 반드시 재정의해야 합니다.

    interface A { void test(); }
    interface B { void test(); }
    
    class C implements A, B {
        @Override
        public void test() { // 중복된 메서드를 하나만 구현해야 함.
            System.out.println("Test");
        }
    }

    5. 정리

    추상 클래스와 인터페이스는 객체 지향 프로그래밍에서 필수적으로 이해해야 하는 개념입니다.

    객체 지향 프로그래밍에서 추상화를 구현하고 코드의 유연성, 재사용성, 유지보수성을 높이는 데 필수적인 도구입니다. 이들의 특징과 사용 시점을 명확히 이해하고, SOLID 원칙과 같은 설계 원칙을 준수하면서 적절하게 활용하면 고품질의 소프트웨어를 개발할 수 있습니다. 또한, Java 8 이후의 인터페이스 기능들을 활용하여 더욱 유연하고 확장 가능한 코드를 작성할 수 있습니다.
    각각의 목적과 특징을 잘 파악하여 적절한 상황에서 활용하는 것이 중요합니다.

    이제, 코드 작성 시 적절한 방식을 선택할 수 있도록 연습해보시기 바랍니다. 😊

    728x90
    반응형