[java]추상클래스와 인터페이스


추상 클래스와 인터페이스

  • abstract
  • interface
  • implements
  • 공통점
  • 차이점


abstract


abstract class 클래스명 {
    abstract 접근제어자 리턴타입 메서드명();  
}

abstract 키워드를 사용하여 추상 클래스나 추상 메서드를 선언할 수 있다. 추상 클래스란 추상 메서드를 선언할 수 있는 클래스를 말하며, 추상 메서드는 선언부만 존재하고 구현부가 없는 메서드를 말한다.

추상 클래스는 인스턴스를 생성할 수 없으며, 추상 메서드는 없어도 된다. 추상 메서드가 없어도 인스턴스 생성은 여전히 불가.

abstract class Player {
    boolean pause;
    abstract void play();
    public abstract void stop();
    protected abstract void pause();
}

class CDPlayer extends Player {
    @Override
    void play() {
        ...
    }

    @Override
    public void stop() {
        ...
    }

    @Override
    protected void pause() {
        ...
    }
}

그리고 추상 메서드는 private 접근 제어자를 적용할 수 없다.

추상 클래스를 상속받은 클래스를 구현할 때 추상 메서드가 존재한다면 반드시 해당 메서드를 오버라이드 해야 한다.

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

        Parent parent = new Parent(); // compile error: Cannot instantiate the type Parent
        Parent.a = "1123";
        Parent.m01(); // 클래스 메서드

        Child child = new Child();
        child.b = "abcd";
        child.m02(); // 인스턴스 메서드
    }
}

abstract class Parent {
    public static String a;
    public String b;

    public static void m01() {
        System.out.println("클래스 메서드");
    }

    public void m02() {
        System.out.println("인스턴스 메서드");
    }
}

class Child extends Parent {
    // have nothing
}

추상 클래스는 클래스 멤버와 인스턴스 멤버를 모두 소유할 수 있다. 이 중 클래스 멤버는 다른 일반 클래스와 동일하지만, 인스턴스 멤버의 경우 추상 클래스의 인스턴스를 생성할 수 없는 문제가 있으므로 항상 추상 클래스를 상속받은 자식 클래스를 통해 접근해야 한다.


interface


interface 인터페이스명 {
    [public ]static final 변수타입 변수명 = ;
    [public ]메서드명();
}

인터페이스는 추상 클래스와 달리 인스턴스 변수를 선언할 수 없으며 추상 메서드와 static 메서드, default 메서드, static final 클래스 변수만 선언할 수 있다. 인터페이스에서 추상 메서드는 abstract 키워드를 생략해도 된다. 인스턴스를 생성할 수 없다는 점은 추상 클래스와 동일하다.

인터페이스의 모든 멤버는 public이 암시적으로 적용된다. 따라서 public은 생략할 수 있다. 반대로 이 말은 public이 아닌 멤버는 인터페이스에 선언할 수 없다는 말이 된다.

interface ImplementMe {
    final String oneTwoThree = "123";
    final String fourFiveSix = "456";

    static String getAng() {
        return "ang?";
    }

    String getText2();

    default String sayHello() {
        return "Hi.";
    }
}

정리하면 인터페이스에 존재 가능한 멤버는 다음과 같다:

  • public static final 필드
  • public static 메서드
  • public abstract 메서드
  • public default 메서드

여기서 default 메서드란, 오직 인터페이스에서만 선언할 수 있으며 구현체에서 별도의 implement 없이 사용할 수 있는 메서드를 말한다.


implements


인터페이스를 구체화한 클래스에서 사용하는 키워드. 구체화 클래스는 인터페이스의 추상 메서드를 반드시 재정의해야한다. extendsimplements 모두 상속의 개념이다. 단, 클래스는 클래스끼리 extends 해야하며 인터페이스는 인터페이스끼리 extends 해야한다.

class Parent { }
class Child extends Parent { }

interface I_Parent { }
interface I_Child extends I_Parent { }

interface I_Parent { }
class Child implements I_Parent { }


공통점


추상클래스와 인터페이스는 선언만 있고 구현 내용이 없는 클래스다.

(자바8부터 인터페이스에 default method 구현이 가능해졌지만 일반적으로 인터페이스는 구현이 없다.)

따라서 인터페이스와 추상클래스를 가지고 새로운 인스턴스(객체)를 생성할 수 없다.

추상클래스를 extends로 상속받아 구현한 자식클래스나 인터페이스를 implements 하고 구현한 자식클래스만이 객체를 생성할 수 있다. 하지만 추상 메소드는 한개만 extends 할 수 있고, 인터페이스는 여러개implements할 수 있다.

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

차이점


상속할 수 있는 개수의 차이도 있지만, 상속 했을 때 구현되는 메서드나 변수의 접근 제한자에서도 차이가 발생한다.

인터페이스에서 상수의 기본 형태는 public static final이고, 메소드는 public abstract형태이다. 따라서 이를 implements한 클래스의 메소드도 모두 public 형태로 구현되어야 한다.

그러나 추상 클래스는 다양한 접근 제한자(public, protected, private)를 가질 수 있다. 따라서 추상 클래스에서는 상속한 이후에도 그보다 하위의 접근 제한자를 가진 메서드와 변수를 구현할 수 있게 된다.

JDK7까지는 추상 클래스에서는 추상 메소드와 일반 메소드를 모두 구현할 수 있었는데 인터페이스는 추상 메소드 작성만 가능해 용도의 정확한 차이까진 모르더라도, 추상 클래스는 구현된 메서드도 있는 클래스 정도로 기억할 수 있었다. 그런데 JDK8이 되면서, 인터페이스에 default 메소드가 추가되었고, 일반 메소드도 구현이 가능해졌다.


언제 추상 클래스를 쓰고, 인터페이스를 쓴다는거야?


추상 클래스

  • public 이외의 접근 제어자가 필요한 경우
  • non-static, non-final 필드가 필요한 경우
  • 관련성이 높은 클래스 간 코드를 공유하려는 경우

인터페이스

  • 다중 사용을 허용하고 싶은 경우
  • 관련성이 낮은 클래스 간 메소드를 공유하려는 경우



[참조]

https://noritersand.github.io/java/java-%EC%B6%94%EC%83%81-%ED%81%B4%EB%9E%98%EC%8A%A4%EC%99%80-%EC%9D%B8%ED%84%B0%ED%8E%98%EC%9D%B4%EC%8A%A4-abstract-classes-interfaces/

https://2ssue.github.io/base/190530_PJI/




© 2021. by Hojin Ahn

Powered by 🐯