본문 바로가기

Java

추상 클래스와 인터페이스

추상 클래스 (abstract)

클래스가 설계도라면 추상 클래스는 미완성 된 설계도 abstract 키워드로 선언 할 수 있음

미완성 된 설계도에는 완성되지 않은 추상 메서드를 선언하고 추상 클래스를 상속 받는 자식 클래스에서 구체화 시키게 할 수 있음

상속받은 클래스에서는 추상 클래스의 추상 메서드를 반드시 오버라이딩 해야 함!

public abstract class Car {
    String company; // 자동차 회사
    String color; // 자동차 색상
    double speed;  // 자동차 속도 , km/h

    public double gasPedal(double kmh) {
        speed = kmh;
        return speed;
    }

    public double brakePedal() {
        speed = 0;
        return speed;
    }

    public abstract void horn();
}

위 Car 추상 클래스를 상속 받아서 자식 클래스에서 구체화 시킬 수 있음

public class ZenesisCar extends Car {

    @Override
    public void horn() {
        System.out.println("Zenesis 빵빵");
    }
}

// Main 클래스
public class Main {
    public static void main(String[] args) {
        Car car1 = new BenzCar();
        car1.horn();
        System.out.println();

        Car car2 = new AudiCar();
        car2.horn();
        System.out.println();

        Car car3 = new ZenesisCar();
        car3.horn();
    }
}

인터페이스 (Interface)

인터페이스는 스팩이 정의된 메서드들의 집합으로 두 객체를 연결해주는 다리 역할을 해줌

상속 관계가 없는 다른 클래스들이 서로 동일한 행위 즉, 메서드를 구현해야 할 때 인터페이스는 구현 클래스들의 동일한 사용 방법과 행위를 보장해 줄 수 있음

//- 모든 멤버변수는 public static final 이어야합니다.
//    - 생략 가능합니다.
//- 모든 메서드는 public abstract 이어야합니다.
//    - 생략 가능합니다. (static 메서드와 default 메서드 예외)
//- 생략되는 제어자는 컴파일러가 자동으로 추가 해줍니다

public interface 인터페이스명 { 
		public static final char A = 'A';
    static char B = 'B';
    final char C = 'C';
    char D = 'D';

    void turnOn(); // public abstract void turnOn();
}

 

  • 인터페이스의 추상 메서드는 구현될 때 반드시 오버라이딩 되어야 합니다.
  • 만약 인터페이스의 추상 메서드를 일부만 구현해야 한다면 해당 클래스를 추상 클래스로 변경해주면 됩니다.
  • 인터페이스 끼리 상속 가능
  • 인터페이스는 클래스와는 다르게 다중 상속이 가능합니다.

 

public class Main extends D implements C {

    @Override
    public void a() {
        System.out.println("A");
    }

    @Override
    public void b() {
        System.out.println("B");
    }

    @Override
    void d() {
        super.d();
    }

    public static void main(String[] args) {
        Main main = new Main();
        main.a();
        main.b();
        main.d();
    }
}
//인터페이스 A와 B를 상속받음
interface A {
    void a();
}

interface B {
    void b();
}

interface C extends A, B {
}

class D {
    void d() {
        System.out.println("D");
    }
}

 

추상클래스 Vs 인터페이스 차이점

추상클래스와 인터페이스의 공통점은 추상메서드를 사용할 수 있다는 것입니다. 그럼 왜 굳이 2가지로 나눠서 사용할까요? 추상클래스와 인터페이스의 기능들을 살펴보면 추상클래스가 인터페이스의 역할을 다 할 수 있는데 왜 굳이 인터페이스라는게 있는 걸까요?

이론적인 차이점을 다 제외하고 두개로 나눠서 사용하는 가장 큰 차이점은 사용용도라고 생각합니다.

 

1. 사용의도 차이점

추상클래스는 IS - A "~이다".

인터페이스는 HAS - A "~을 할 수 있는".

이렇게 구분하는 이유는 다중상속의 가능 여부에 따라 용도를 정한 것 같습니다. 자바의 특성상 한개의 클래스만 상속이 가능하여 해당 클래스의 구분을 추상클래스 상속을 통해 해결하고, 할 수 있는 기능들을 인터페이스로 구현합니다.

이렇게 글로 표현하여 이해가 어려울 수 있습니다. 아래 예제를 통해 더 자세하게 설명하겠습니다.

 

2. 공통된 기능 사용 여부

만약 모든 클래스가 인터페이스를 사용해서 기본 틀을 구성한다면... 공통으로 필요한 기능들도 모든 클래스에서 오버라이딩 하여 재정의 해야하는 번거로움이 있습니다. 이렇게 공통된 기능이 필요하다면 추상클래스를 이용해서 일반 메서드를 작성하여 자식 클래스에서 사용할 수 있도록 하면 된다. 어!? 그러면 그냥 추상클래스만 사용하면 되는 거 아닌가요? 위에서 얘기 했듯이 자바는 하나의 클래스만 상속이 가능합니다. 만약 각각 다른 추상클래스를 상속하는데 공통된 기능이 필요하다면? 해당 기능을 인터페이스로 작성해서 구현하는게 편하겠죠?

 

아무래도 글로만 설명하는데는 한계가 있는 것 같습니다. 아래 예제를 통해 어떻게 언제 무엇을 사용해야할지 알아 보도록 합시다.

 

추상 클래스 인터페이스 예제 (생명체 도메인)

위와 같은 관계를 갖는 예제를 만들어 보겠습니다. 인간과 동물은 생명체를 상속하고 각 생명체들은 구분에 따라 인간과 동물을 상속합니다. 그리고 각각 할 수 있는 기능들을 인터페이스로 구현했습니다.

 

 

Creature 추상 클래스

public abstract class Creature {
    private int x;
    private int y;
    private int age;
    
    public Creature(int x, int y, int age) {
        this.age = age;
        this.x = x;
        this.y = y;
    }
    
    public void age() {
        age++;
    }
    
    public void move(int xDistance) {
        x += xDistance;
    }
    
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    
    public abstract void attack();
    public abstract void printInfo();
    
    @Override
    public String toString() {
        return "x : " + x + ", y : " + y + ", age : " + age;
    }
}

기본적으로 생명체가 갖는 요소로 위치 x, y그리고 age 나이가 필요하다고 생각하여 선언했고 생성자가 만들어 질때 이 3가지 요소는 받아서 넣을 수 있도록 했습니다. toString 메서드는 나중에 출력은 간편하게 하기 위해서 오버라이딩하여 사용했습니다. 

생명체라면 나이를 먹고 x좌표상으로 이동 할 수 있는 부분이 공통 적인 기능이기 때문에 하위 클래스에서 상속할 수 있도록 일반 메서드로 구현했습니다.

추상메서드로는 공격하는 기능과 정보를 출력하는 기능을 선언했습니다. 모든 생명체에 필요한 기능이지만 각각 생명체에 따라 다른 기능으로 구현을 해야하기 때문에 위 두 메서드는 추상메서드로 선언하여 하위클래스에서 처리하도록 한 것입니다.

Creature 추상 클래스

 

https://myjamong.tistory.com/150

 

정리

  • 추상클래스 사용 시기 : 상속 관계를 쭉 타고 올라갔을때 같은 조상클래스를 상속하는데 기능까지 완변히 똑같은 기능이 필요한 경우
  • 인터페이스 사용 시기 : 상속 관계를 쭉 타고 올라갔을때 다른 조상클래스를 상속하는데 같은 기능이 필요할 경우 인터페이스 사용

'Java' 카테고리의 다른 글

변수 및 자료구조 타입에 대한 사용 예제  (0) 2023.04.07
default, static, 다형성  (0) 2023.04.05
접근제어자  (0) 2023.04.05
기본형 & 참조형 매개변수  (0) 2023.04.04
오버로딩 및 오버라이딩  (0) 2023.04.04