java

[Java] 추상클래스(abstract class)와 인터페이스

소리소리솔소리 2023. 5. 3. 13:58

추상 클래스(abstract class)

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

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

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

 

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

 

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(); // 야옹
    }
}

 

 

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

→ 구현이 가능하다

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(); //냠냠
    }

 

 

인터페이스(interface)

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

  • 인터페이스는 추상 클래스보다 한 단계 더 추상화 된 클래스라고 볼 수 있다.→ 기존에는 인터페이스에 일반 메서드를 구현할 수 없었지만, 자바 8버전부터 default 예약어를 통해 일반 메서드 구현이 가능하다.
  • → 인터페이스에 적는 모든 메서드들은 추상 메서드로 간주되기 때문에 abstract를 적지 않는다.
  • 인터페이스는 static final 필드만 가질 수 있다. 필드를 선언할 때 public static final이 생략되어 있다고 생각하자.
    1. 구현 객체의 같은 동작을 보장하기 위한 목적
    2. 인터페이스의 변수는 스스로 초기화 될 권한이 없음
    3. 아무 인스턴스도 존재하지 않는 시점이기 때문
  • → 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(); // 크아앙
											// 밥을 냠냠 먹는다.
    }
}

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

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

 

[ 추상 클래스와 인터페이스의 공통점 ]

  • 추상 클래스와 인터페이스는 선언부만 있고 구현은 없는 클래스이다. (자바 8부터 인터페이스에서 default method로 구현이 가능하지만 일반적으로 구현은 없다.)
  • 인스턴스화(객체 생성 X)를 할 수 없다.
  • 추상 클래스를 extends로 상속받은 자식들과 인터페이스를 implments하고 구현한 자식들만 객체 생성 가능 → 자식 클래스가 무언가 반드시 구현하도록 위임해야 할 때 사용한다.

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

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