멋사 부트캠프/Java 프로그래밍

07. 추상 클래스 & 인터페이스

cTosMaster 2025. 3. 11. 17:42

1. 인터페이스

    인터페이스가 가진 모든 것들을 재정의하여 사용할 것을 강력하게 강제하고자 할 때, 사용한다.

   

1) 인터페이스는 동적 바인딩이 자동으로 이루어진다.

  • 왜냐하면, 인터페이스의 모든 메서드는 abstract이므로, 이를 구현하는 클래스에서 반드시 오버라이딩해야 한다.
  • 그로 인해, 인터페이스 타입의 객체에서 메서드를 호출해도, 결국 구현 클래스의 오버라이딩된 메서드가 실행된다. (덮어쓰기 개념)

2) "인터페이스 참조변수 = new 구현 클래스();"

  • 위 방식으로 객체를 생성하면, 별도의 캐스팅 없이도 구현 클래스의 오버라이딩된 메서드를 호출할 수 있다.
  • 단, 구현 클래스의 인터페이스 메서드만 호출 가능하며, 구현 클래스의 독립적인 메서드는 호출할 수 없다.
interface Animal {
    void makeSound();
}

class Dog implements Animal {
    @Override
    public void makeSound() {
        System.out.println("멍멍!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal myPet = new Dog(); // 인터페이스 타입으로 객체 생성
        myPet.makeSound(); // "멍멍!" 출력 (동적 바인딩)
    }
}

✅ 언제 인터페이스에서 상수를 사용할까?

더보기

1️⃣ 여러 클래스에서 공통적으로 사용되는 값이 있을 때

  • 예를 들어, 상태 코드, 설정 값, 단위 같은 변하지 않는 값들을 인터페이스에 정의하면 좋음.

2️⃣ 상수를 일관성 있게 사용하고 싶을 때

  • 하드코딩을 방지하고, if문이나 switch문에서 가독성을 높일 수 있음.

3️⃣ 인터페이스를 구현하는 모든 클래스에서 해당 상수를 참조할 때

  • 따로 implements를 하지 않아도, 인터페이스명.상수명으로 접근 가능!

 

2. 추상 클래스

    부모 클래스가 가진 일부의 기능들을 특정하여 재정의 해 사용하게끔 할 때, 사용한다. 

 

    1) 추상 클래스는 업캐스팅으로 동적바인딩을 구현한다.( "부모클래스 참조변수 = new 구현 자식 클래스();")

     

    2) "부모클래스 참조변수 = new 구현 자식 클래스();"

         위와 같이 생성하면 스택 영역에 부모 객체의 주소가 올라오고 힙 영역에 자식 객체가 생성이 되는데, 

         이 때, 부모 클래스의 주소를 활용하여 자식 클래스에서 필요한 것만을 호출하기 위한 것이다.

         이것을 동적 바인딩이라고 한다.  

         a. "(자식클래스)참조변수.(자식메서드)"와 같이 다운캐스트하여 사용할 때

              -> 자식 클래스에서 독립적인 메서드를 생성한 경우이다.
              -> 다른 방식으로, foreach-instanceof 구문을 활용하여 확인 후 호출하기도 한다.       

public class Main {
    public static void main(String[] args) {
        Parent[] arr = { new ChildA(), new ChildB(), new Parent() }; // 부모 타입 배열

        for (Parent p : arr) {
            if (p instanceof ChildA) {
                ((ChildA) p).specialMethodA(); // ChildA 타입일 경우 실행
            } else if (p instanceof ChildB) {
                ((ChildB) p).specialMethodB(); // ChildB 타입일 경우 실행
            } else {
                p.show(); // 부모 클래스 메서드 실행
            }
        }
    }
}

         b. 그 외, 자식 객체에서 오버라이딩한 메서드들은 부모 객체에서 덮어쓰기 되어버려 캐스트하지 않아도

             자식 메서드가 바로 호출된다. 

         

 

🔹 초간단 요약 정리

인터페이스(스케치) → 기능(메서드)만 선언하고, 내부 로직은 없음
추상 클래스(정의) → 일부 구현이 포함될 수 있으며, 공통된 로직 제공 가능
메인 클래스(구현) → 추상 클래스를 상속받거나 인터페이스를 구현해서 최종 기능 완성

 

가급적이면 루트 클래스에 implements를 하는 것이 코드 재사용을 방지하고 유지보수하기 편하다.