(Java) Interface와 Abstract class의 차이(인터페이스와 추상클래스)

2022. 7. 16. 18:38Java

반응형

백엔드 개발자이고 면접을 준비하고 있거나, 면접을 봐본 사람이라면 이 질문에 대해서 고민 해봤을 것이다.

언뜻 보면 둘이 비슷하게 생겼다.

외부적으로는 선언된 방식이 interface냐 abstract class냐의 차이가 있지만 말이다.

그럼 각각에 대해서 알아보도록 하자.

🧐Interface


먼저 인터페이스 코드를 보자.

public interface Dog {
    void bark();
    
    void walk();
}


Dog라는 interface에는 두가지 메서드가 있다.

하나는 bark(), 하나는 walk()

각각의 메서드는 추상 메서드인가?


앞에 abstract가 없는데도 추상 메서드인가?


그렇다.

interface가 가지고 있는 메서드는 모두 추상 메서드이다.


그럼 정말 모두 추상 메서드일까?


다음의 코드를 보자.

public interface Dog {
    default void bark() {
        System.out.prinln("멍멍");
    }
    
    void walk();
}


이건 어떤가?

모두 추상메서드라고 했는데 동작이 포함된 메서드가 있다.

어떻게 된 일일까?


이것은 자바 8버전 이후에 추가된 '기본 메서드'라는 것이다.


이름만 들어도 기본 메서드의 기능을 알 수 있지 않은가?


구현체에서 따로 구현하지 않는다면 기본 메서드에서 정의된 동작을 그래도 실행할 것이다.

🧐Abstract Class


이번에는 추상클래스를 살펴보자.

public abstract class Dog{
    public abstract void bark();
    
    public void walk() {
        System.out.print("I can walk");
    }
}



추상 클래스는 인터페이스와 달리 추상 메서드를 따로 추상 메서드라고 선언해야한다.


그리고 그렇지 않다면 반드시 구현을 해줘야한다.


🧐Interface vs Abstract Class


그럼 인터페이스와 추상클래스의 차이는 뭘까?

둘은 존재 목적에서 큰 차이를 보여준다.

인터페이스의 목적은 같은 동작 보장에 있다.

추상 클래스의 목적은 상속에 있다.

가장 간단한 예시를 들어보자.

public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findById(Long id);
}


Spring Data Jpa에서 가장 많이 쓰이는 간단한 findById이다.

이 인터페이스를 구현하는 구현체는 어떠한 방식으로든지 findById를 하는 것이다.


for문을 돌리든, 람다를 사용하든, 그것은 객체지향에서 다형성의 이점이기에 전혀 상관없는 문제다.


결국 이 인터페이스는 Optional<User>를 찾아서 돌려줄 것이라는 동작의 보장이 있는 것이다.




추상 클래스의 목적은 상속에 있다고 했다.

아래의 슈퍼 클래스 코드와 자식 클래스 코드를 보자.

슈퍼 클래스 코드

// Super Class
public abstract class Person {
    private String name;
    
    public Person(String name) { this.name = name;}
    
    public final String getName() { return name;}
    
    public abstract int getId();
    
}


서브 클래스 코드

// Subclass
public class Student extends Person {
    private int id;
    
    public Student(String name, int id) {
        super(name); this.id = id;
    }
    
    public int getId() { return id;}
 }


이렇게 Person 클래스를 상속받은 Student 클래스는 마법같은 일이 벌어진다.

class Main {
    public static void main(String[] args) {
        Person p = new Student("Hoo", 20);
    }
}


바로 추상 클래스타입으로 변수 선언이 가능하다는 것이다.


이렇게 되면 변수 Student 클래스로 인스턴스를 생성했지만, 마치 Person 클래스의 인스턴스를 생성한 것과 같은 효과를 낸다.


이것이 가능한 이유는 바로 추상 클래스는 인터페이스와 다르게 생성자와 인스턴스 변수를 포함할 수 있기 때문이다.


정리


그럼 정리해보자.

종류 인터페이스 추상 클래스
목적 같은 동작의 보장 상속
생성자 유무 X O
인스턴스 변수 유무 X O
인스턴스 생성 여부 X X
하위 클래스에 상위 생성자 호출 X O


반응형