추상 클래스

클래스를 설계도라고 했다면 추상클래스는 미완성 설계도라고 할 수 있다. 미완성 설계도란 말그대로 덜 만들어진 설계도이다.
클래스가 미완성이라는 것은 단지 미완성 메서드(추상 메서드)를 포함하고 있다는 의미이다. 미완성 설계도 만으로 온전한 상품을 만들 수 없듯이 추상클래스 만으로 객체를 생성할 수 없다. 추상 클래스는 상속을 통해 자식클래스에 의해서만 완성될 수 있다.

추상클래스의 역할과 사용법

추상클래스 자체만으로는 클래스로서의 역할을 못하지만, 새로운 클래스를 작성하는데 있어서 바탕이 되는 부모클래스로서 중요한 의미를 갖는다.
예를 들어서 볼펜에는 다양한 볼펜이 있을 것이다. 이들 모두 조금씩 모양이나 특징이 다르더라도 이들의 설계도(제작도)는 90% 이상이 일치할 것이다. 서로 다른 설계도를 모두 그리는 것 보다는 이들의 공통점만 그린 미완성 설계도를 만들어 놓고 이를 이용해 완제품을 만드는게 효율적일 것이다.

추상 클래스는 'abstract' 키워드를 붙이기만 하면 된다.

abstract class 클래스이름 {
    // ...
}

이렇게 하면 클래스 선언부의 abstract를 보고 추상클래스임을 바로 알수가 있다.
추상클래스는 추상메서드를 포함하고 있다는 점을 제외하고는 일반적인 클래스와 똑같다.

추상 메서드

메서드는 선언부와 구현부로 구성되어있다.
선언부만 작성하고 구현부는 작성하지 않은 메서드가 추상메서드이다.

public void doing() { // 선언부
    // 구현부...
}

예제

다음은 추상클래스의 예제이다.

public class Animal extends AnimalValue {

    String sound;

    // 추상메서드 구현(재정의)
    @Override
    void sound(String sound) {
        this.sound = sound;
    }

    @Override
    void behavior() {
        System.out.println(sound);
    }

    public static void main(String[] args) {
        Animal tiger = new Animal();

        tiger.sound("어흥");
        tiger.behavior();
    }
}

// 추상클래스
abstract class AnimalValue {
    abstract void sound(String sound);
    abstract void behavior();
}

@Override는 어노테이션 종류 중 하나인데, 간단히 설명하자면, 이것이 붙은 메서드는 반드시 부모클래스나 인터페이스에 명시되어야 한다. 재정의를 할때 오타로 인한 오류를 막아주는 역할이라고 생각하면 편하다.

인터페이스(Interface)

인터페이스도 추상클래스와 크게 다르지 않다.
인터페이스도 일종의 추상클래스이다. 인터페이스는 추상클래스보다 추상화 정도가 높아서 구현부를 지닌 일반 메서드 또는 멤버변수를 가질 수 없다. 오직 추상메서드와 상수만을 구성원으로 가질 수 있다.
추상클래스가 '미완성된 설계도'라고 한다면 인터페이스는 오직 밑그림만 있는 '기본 설계도'라고 할 수 있다.

인터페이스 선언

인터페이스를 선언하는 것은 클래스를 선언하는 것과 다를바가 없다. class 키워드 대신 interface 키워드를 사용하기만 하면 된다. 그리고 interface도 클래스와 같이 접근지정자를 사용할 수 있다.

interface 인터페이스이름{
    public static final 타입 이름 =;
    public abstract 메서드이름 (매개변수);
}

일반적인 클래스와 달리 인터페이스의 멤버들은 다음과 같은 제약 조건이 있다.

  1. 모든 멤버변수는 public static fianl 이어야 하며, 이를 생략할 수있다.
  2. 모든 메서드는 public abstract 이어야 하며, 이를 생략할 수 있다.
단 static메서드와 디폴트 메서드는 예외이다.(jdk1.8부터)

이 제약조건들은 예외없이 적용되는 사항이기 때문에 제어자를 생략할 수 있는 것이며,
편의상 생략하는 경우가 많다. 생략된 제어자는 컴파일러가 컴파일 시 자동으로 추가해준다.

인터페이스의 상속

인터페이스는 인터페이스로부터만 상속받을 수 있다. 클래스와는 다르게 다중 상속이 가능하다.

interface A {
    void doingA();
}

interface B {
    void doingB();
}

interface C extends A, B {

}

클래스의 상속과 마찬가지로 자식 인터페이스는 부모 인터페이스에 정의된 멤버를 모두 상속 받는다.

인터페이스의 구현

인터페이스도 추상클래스처럼 그 자체로는 객체를 생성할 수 없으며, 추상클래스가 상속을 통해 추상메서드를 완성하는 것처럼, 인터페이스도 자신에게 정의된 추상메서드의 구현부를 만들어주는 클래스를 작성해야 한다. 추상클래스는 extends 키워드를 통해 구현했다면 인터페이스는 implements 키워드를 사용한다.

interface interfaceExample {
    int NUMBER = 1; // public static final int NUMBER = 1;

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

class useInterface implements interfaceExample {

    @Override
    public void getNumber() {
        // 재정의...
    }
}

이렇듯 인터페이스도 추상클래스와 비슷하게 구현가능하다.

인터페이스의 장점

그러면 인터페이스를 사용하는 이유는 무엇일까?

1. 개발시간을 단축시킬 수 있다.

  • 개발자들이 각각의 부분을 완성할 때까지 기다리지 않고
    서로 규약만 정해두어 각자의 부분만 따로 나눠서 작성된 코드를 컴파일 할 수 있다.

2. 표준화가 가능하다.

  • 클래스의 기본틀을 제공하여 개발자들에게 정형화된 개발을 강요할 수 있다.

3. 서로 관계없는 클래스들에게 관계를 맺어 줄 수 있다.

  • 코드의 종속성을 줄이고 유지보수성을 높이도록 해준다.
    즉 클래스들끼리의 쓸데없는 상속을 줄일 수 있다.

4. 독립적인 프로그래밍이 가능하다.

  • 클래스와 클래스간의 직접적인 관계를 인터페이스를 통해 간접적인 방법으로 변경하면,
    한 클래스의 변경이 다른 클래스에 영향을 미치지 않는 독립적인 프로그래밍이 가능하다.

인터페이스와 추상클래스를 나도 지금까지 그렇게 많이 사용하지 않아 여러 가지 팁? 같은것을 알려주기는 힘들지만 여러 개발 활동을 통해 오늘 보다 더 나은 지식을 얻기를 바라겠습니다.😊