본문 바로가기

CS study/java

[Java] 인터페이스와 추상 메서드, 일반 메서드

목차

    추상클래스가 생긴 이유가 뭘까?

    추상 클래스는 자체적으로 인스턴스로 구현할 수 없다.
    = 인스턴스로 구현하고 싶다면 하위 클래스가 상속(extend) 추상적인 부분을 Override로 구현해야 한다!

     

    상속을 받는데, 내 하위 클래스가 이 기능(메서드)를 가지게 하고 싶다.

    근데 무슨 기능인지는 잘 모르지만.. 어쨌든 구현해야 한다!!

     

    아마도 일반 메서드와 가장 큰 차이라고 생각한다.

    그럼 구현하지도 못할 메서드를 도대체 왜 사용하는 걸까? 추상 클래스가 있는 이유는 여러 가지다.

     

    1. 공통 로직 중복 제거
      상속을 받는 하위 클래스들이 공통으로 사용하는 로직이나 속성을 한 곳에서 관리할 수 있다.
      = 추상 메서드를 상속받는 하위 클래스들은, 추상클래스의 메서드를 공통으로 가지게 된다.

    2. 템플릿 제공
      추상 클래스에서 메서드의 기본 구조나 흐름을 정의하고, 하위 클래스에서 이를 확장할 수 있다. (Override)

    3. 강제 규약
      추상 클래스는 하위 클래스가 특정 메서드를 구현하도록 강제한다.
      이로써 일관된 인터페이스를 유지할 수 있다.

    4. 코드의 안정성
      추상 클래스를 사용하면 해당 클래스의 인스턴스를 직접 생성할 수 없으므로, 미구현된 클래스가 객체로 생성되는 것을 막을 수 있다.
      인스턴스로 구현하려면 추상적인 부분을 Override를 통해 구체화하면 된다.

    추상 클래스는 이런 이유로 디자인 패턴, 라이브러리 구현, 공통 로직의 재사용 등 다양한 상황에서 유용하게 사용된다.

    // 추상 클래스
    public abstract class Animal {
      private String name;
    
      public Animal(String name) {
        this.name = name;
      }
    
      public void eat() {
        System.out.println(name + " is eating.");
      }
    
      //추상적인 부분 : 상속받을 때 구현해야 함!
      public abstract void makeSound();
    }
    
    public class Dog extends Animal {
      public Dog(String name) {
        super(name);
      }
    
      @Override
      public void makeSound() {
        System.out.println("Woof!");
      }
    }
    
    // 사용 예
    Animal myDog = new Dog("Buddy");
    myDog.eat();        // 출력: Buddy is eating.
    myDog.makeSound();  // 출력: Woof!

     

     

     

    그렇다면 추상 메서드와 인터페이스의 차이는?

    인터페이스를 처음 학습할 때는 GUI의 규격, 즉 모든 개발자들이 인터페이스를 통해 같은 규격의 서비스 혹은 비즈니스 로직 코드를 작성할 수 있다고 배웠다.

     

    처음 느꼈던 건 추상 메서드가 있는데 왜 인터페이스가 필요할까? 라는 의문이었다.

    일단 인터페이스를 구현할 때 느꼈던 명확한 차이는 '인터페이스는 기본적으로 추상과 final(생략) 으로 메서드가 선언되고, {} 의 구현부가 존재하지 않는다' 는 점이다.

    (물론 자바 8 이후 default나 static이 도입되어 무조건 추상일 필요는 없다. 또한 public static final 형태의 변수를 가질 수도 있다고 한다. - 수정한 부분)

     

    이러한 점에서, 추상 메서드와 인터페이스의 차이를 생각해보면 다음과 같다.

     

    1. 추상 클래스는 추상 메서드뿐만 아니라 구체적인 메서드, 변수를 가질 수 있다.

    이는 추상 클래스는 공통 로직이 존재하고, 필요한 부분만 하위 클래스에서 각자 구현(Override) 하기 때문이다.

    즉, 강제로 구현하는 공통 부분이 일부이다.

    인터페이스는 해당 인터페이스의 모든 메서드를 구현해야 한다.

     

    2. 다중 상속

    일반적으로 클래스는 하나의 상속만을 허용한다. 마찬가지로 하위 클래스는 하나의 추상 클래스만 상속받을 수 있다.

    그런데 공통적으로 상속 받을 것이 여러개라면? 인터페이스를 사용하여 여러 추상 메서드를 상속받을 수 있다.

    마치 인터페이스를 통해 다중 상속을 받는 것과 유사한 기능을 제공받을 수 있는 것이다.

    그렇기에 모든 인터페이스의 메서드는 기본적으로 추상 메서드이며, 상속 시 모든 추상 메서드를 구현해야 한다.

     

    결론 : 인터페이스를 사용하는 이유?

    인터페이스를 구현한다면, 모든 메서드를 동일한 규격으로 가지고 있게 된다.
    즉, 여러 공통 기능을 가진 설계도가 된다.

     

    추상 클래스의 확장 버전이라고 생각한다.

    공통적으로 필요한 로직이 있을 때, 이를 각자 상속받아서 구현한다.

     

    추상 메서드는 하위 클래스에게 일부 공통(Override하는) 부분을 강제하고, 부모의 메서드나 변수 등을 상속한다면

    인터페이스는 변수나 기능을 상속받기 보다는 모듈화를 하기 위해 모든 부분을 규격화하는 과정에 조금 더 가깝다는 생각이 들었다.

    따라서 모든 구성 요소가 추상 메서드이고, 변수는 존재하지 않으며 이를 구현하는 과정에서 각자 기능을 확장하고 구현하는 것이다.