슬기로운 개발생활

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

by coco3o
반응형
추상 클래스(abstract class)

추상 클래스는 클래스 구현부 내부에 추상 메소드가 하나 이상 포함되거나 abstract로 정의된 경우를 말한다.

abstract class를 상속받은 클래스(하위 클래스)는 자기의 성질에 맞게 Overriding하여 사용한다.

 

  • 추상 클래스는 new 연산자를 사용하여 객체를 생성할 수 없다.
  • 추상 클래스(부모)와 일반 클래스(자식)는 상속의 관계에 놓여있다.
  • 추상 클래스는 새로운 일반 클래스를 위한 부모 클래스의 용도로만 사용된다.
  • 공통된 필드와 메소드를 통일하여 일반 클래스 작성 시 시간을 절약할 수 있다.
  • 추상 클래스는 단일 상속만 가능하며 일반 변수를 가질 수 있다.
  • 추상 클래스는 동일한 부모를 가지는 클래스를 묶는 개념으로 상속을 받아서 기능을 확장시키는 것이 목적이다.

추상 클래스를 설명하기 위해 Animal 추상 클래스를 선언해보자.

public abstract class Animal {

    public abstract void sound();
}

어떤 A라는 클래스가 추상클래스를 상속 받는다면 A클래스는 추상클래스에 선언되어있는 추상메소드를 반드시 구현해야한다.

 

아래는 Animal 추상클래스를 상속받은 일반 클래스이다.

public class Dog extends Animal{
    @Override
    public void sound() {
        System.out.println("멍멍");
    }
}
public class Cat extends Animal{
    @Override
    public void sound() {
        System.out.println("야옹");
    }
}

 

public class Main {
    public static void main(String[] args) {

        Dog dog = new Dog();
        Cat cat = new Cat();

        dog.sound();
        cat.sound();
    }
}
멍멍
야옹야옹
Process finished with exit code 0

추상 클래스에서는 일반 메소드를 구현할 수 없을까?

구현이 가능하다.

Dog와 Cat의 sound는 각기 다르지만 밥을 먹는 행위는 공통적이므로 Animal 추상 클래스에 eat 메소드를 만들어보자.

public abstract class Animal {

    public abstract void sound();
    
    public void eat() {
        System.out.println("냠냠");
    }
}
public class Main {
    public static void main(String[] args) {

        Dog dog = new Dog();
        Cat cat = new Cat();

        dog.sound();
        cat.sound();

        dog.eat();
        cat.eat();
    }
멍멍
야옹
냠냠
냠냠
Process finished with exit code 0

위를 보면 알 수 있듯이  abstract는 일반 메소드를 사용할 수 있다.


인터페이스(interface)

인터페이스는 모든 메소드가 추상 메소드인 경우를 말한다.

 

  • 인터페이스는 추상 클래스보다 한 단계 더 추상화된 클래스라고 볼 수 있다.
    • 인터페이스에 적는 모든 메소드들은 추상 메소드로 간주되기 때문에 abstract를 적지 않는다.
    • 기존에는 인터페이스에 일반 메소드를 구현할 수 없었지만, 자바 8버전부터 default 예약어를 통해 일반 메소드구현이 가능하다.
  • 인터페이스는 static final 필드만 가질 수 있다. 필드를 선언할 때 public static final이 생략되어 있다고 생각하자.
    • public static final을 사용하는 이유는 다음과 같다
    • 구현 객체의 같은 동작을 보장하기 위한 목적
    • 인터페이스의 변수는 스스로 초기화 될 권한이 없음
    • 아무 인스턴스도 존재하지 않는 시점이기 때문
  • 인터페이스도 추상 클래스와 마찬가지로 new 연산자를 사용하여 객체를 생성할 수 없다.
  • 인터페이스는 구현 객체가 같은 동작을 한다는 것을 보장하는 것이 목적이다.
  • 인터페이스는 추상 클래스와 반대로 다중 상속이 가능하다.

인터페이스에 필드와 메소드를 선언하면 컴파일러가 자동으로 키워드를 붙여 해석한다.


클래스와 인터페이스 사이 관계 이해하기

아래 사진에서 보이는 것 처럼 클래스끼리, 인터페이스끼리 상속할 때는 extends
 클래스가 인터페이스를 상속받을 때는 implements 키워드를 사용한다.


예제로 인터페이스를 이해해보자.

public interface AnimalInterface {

    void sound();
    String eat = "냠냠";
//  public final static String eat = "냠냠";  
}

위와 같이 인터페이스를 생성하고

public class Lion implements AnimalInterface {

    @Override
    public void sound() {
        System.out.println("크아앙");
        System.out.println("밥을 " + eat + " 먹는다.");
    }
}

새로운 클래스를 만들어 인터페이스를 상속받는다. 그리고 출력을 하게되면

public class Main {
    public static void main(String[] args) {
        Lion lion = new Lion();

        lion.sound();
    }
}
크아앙
밥을 냠냠 먹는다.

Process finished with exit code 0

위의 예제는 이해를 돕기 위한 것으로, interface를 정의하는 목적이 아니다.

interface에서 위와 같이 상수를 사용하는 것은 안티 패턴이라고 하는데, 실제 interface에선 위처럼 사용하면 안된다.

상수를 사용해야될 때는 상수만 모아놓은 클래스를 따로 만들어서 사용하자.


추상 클래스와 인터페이스의 공통점
  • 추상 클래스와 인터페이스는 선언부만 있고 구현은 없는 클래스이다.
    • (자바 8부터 인터페이스에서 default method로 구현이 가능하지만 일반적으로 구현은 없다.)
  • 인스턴스화(객체 생성 X)를 할 수 없다.
  • 추상 클래스를 extends로 상속받은 자식들과 인터페이스를 implements하고 구현한 자식들만 객체 생성 가능 

(결국 자식 클래스가 무언가 반드시 구현하도록 위임해야할 때 사용한다.)

 

추상 클래스와 인터페이스의 차이점
  • 추상 클래스(단일 상속) / 인터페이스(다중 상속)
  • 추상 클래스의 목적은 상속을 받아서 기능을 확장시키는 것(부모의 유전자를 물려받는다.)
  • 인터페이스의 목적은 구현하는 모든 클래스에 대해 특정한 메소드가 반드시 존재하도록 강제하는 역할 (부모로부터 유전자를 물려받는 것이 아니라 사교적으로 필요에 따라 결합하는 관계) 즉, 구현 객체가 같은 동작을 한다는 것을 보장하기 위함

 

참고

반응형

블로그의 정보

슬기로운 개발생활

coco3o

활동하기