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

추상 클래스와 인터페이스

추상 클래스

추상 클래스란?

추상 클래스는 abstract 키워드로 선언된 클래스입니다. 추상 클래스의 주요 목적은 여러 하위 클래스에서 공유할 수 있는 공통 특성 및 동작을 정의하는 것입니다.

추상 클래스는 직접 객체를 생성할 수 없습니다. 대신 다른 클래스에 의해 상속되도록 설계되어 추상 메서드에 대한 구현을 제공할 수 있습니다.

public abstract class Animal {
}

public class Main {
  public static void main(String[] args) {
    Animal animal = new Animal(); // 생성 불가
  }
}

추상 클래스도 필드, 메서드를 선언할 수 있습니다. 그리고 추상 클래스도 객체이기 때문에 생성자가 필요합니다.

public abstract class Animal {
  private int age;

  public Animal(int age) {
    this.age = age;
  }

  public void getAge() {
    System.out.println("age: " + age);
  }
}

public class Dog extends Animal {

  public Dog(int age) {
    super(age);
  }
}

public class Main {
  public static void main(String[] args) {
    Dog dog = new Dog(3);

    dog.getAge(); // 3
  }
}

추상 메서드란?

추상 클래스는 하나 이상의 추상 메서드를 포함할 수 있습니다. 추상 메서드는 자식 클래스들마다 선언부는 같지만 구현부는 다른 메서드가 있을 때 사용합니다. 추상 메서드는 abstract 키워드를 붙여 메서드를 선언합니다. 일반 메서드와 다르게 구현부가 없습니다.

abstract 반환타입 메서드명(매개변수1, ...);

추상 클래스를 상속받은 자식 클래스는 부모 클래스가 추상 메서드가 있다면, 반드시 추상 메서드의 구현부를 작성해야 합니다.

public abstract class Animal {
  abstract void sound();
}

public class Dog extends Animal {

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

public class Cat extends Animal {

  @Override
  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(); // 냐옹
  }
}

인터페이스

인터페이스란?

인터페이스는 구현 클래스가 준수해야 하는 가이드라인입니다. 인터페이스는 추상 메서드와 상수만 포함하기 때문에, 무엇을 해야 하는지 정의하지만 어떻게 해야 하는지는 정의하지 않습니다.

인터페이스 선언

인터페이스는 선언 시 interface 키워드를 사용합니다.

interface 인터페이스명 {
  ...
}

인터페이스 구현

인터페이스를 구현하려면 implemnets 키워드 뒤에 구현하려는 인터페이스 이름을 사용해야 합니다. 여러 인터페이스를 구현하려는 경우 쉼표를 사용하여 구분할 수 있습니다.

public class 클래스 implements 인터페이스1, 인터페이스2, ... {
  ...
}

인터페이스를 구현하는 클래스를 선언한 후에는 인터페이스에 선언된 모든 메서드에 대한 구현을 제공해야 합니다.

public interface AInterface {
  void method1();
}

public class A implements AInterface {

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

인터페이스를 구현한 클래스는 객체 생성 시 그 인터페이스를 참조 타입으로 쓸 수 있습니다.

public interface AInterface {
  void method1();
}

public class A implements AInterface {

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

public class Main {
  public static void main(String[] args) {
    AInterface a = new A();
    a.method1(); // method1
  }
}

인터페이스 필드

인터페이스의 필드는 상수로 취급되며, public static final로 선언됩니다. 생략하더라도 자동적으로 컴파일 과정에서 붙게 됩니다.

[public static final] 타입 상수명 = ;
public interface AInterface {
  int VALUE = 10;
}

public class A implements AInterface {
}


public class Main {
  public static void main(String[] args) {
    // static이 붙어 객체 생성 안하고 접근 가능
    System.out.println(A.VALUE); // 10

    A.VALUE = 15; // final로 선언되어 재할당 불가
  }
}

추상 메서드

인터페이스는 구현 클래스가 재정의해야 하는 추상 메서드를 가질 수 있습니다. 인터페이스의 추상 메서드는 앞에 publicabstract가 선언되어야 합니다. 생략하더라도 컴파일 과정에서 자동으로 붙게 됩니다.

추상 메서드가 있는 인터페이스를 구현한 클래스가 있다면 추상 메서드를 반드시 재정의해야 합니다.

public interface AInterface {
  void method1();
}

public class A implements AInterface {
    @Override
    public void method1() { // 재정의 안하면 오류 발생
        System.out.println("method1");
    }
}

public class Main {
    public static void main(String[] args) {
        AInterface a = new A();
        a.method1(); // method1
    }
}

메서드를 재정의할 때 주의할 점은 인터페이스의 추상 메서드는 public 접근 제어자를 갖기 때문에 public보다 더 낮은 접근 제한은 할 수 없습니다.

public interface AInterface {
  void method1();
}

public class A implements AInterface {
    @Override
    protected void method1() { // 오류 발생
        System.out.println("method1");
    }
}

public class Main {
    public static void main(String[] args) {
        AInterface a = new A();
        a.method1(); // method1
    }
}

디폴트 메서드

자바 8부터 인터페이스가 메서드에 대한 기본 구현을 제공할 수 있도록하는 디폴트 메서드가 추가되었습니다. default 키워드를 사용하여 선언하면 됩니다.

public interface AInterface {

    default void method1() {
        System.out.println("method1");
    }
}

public class A implements AInterface {
}

public class Main {
    public static void main(String[] args) {
        AInterface a = new A();
        a.method1(); // method1
    }
}

디폴트 메서드도 재정의가 가능합니다. 주의할 점은 디폴트 메서드도 public 접근 제어자를 갖기 때문에 더 제한된 접근 제어자를 사용할 수 없으며, default 키워드를 생략해야 합니다.

public interface AInterface {

    default void method1() {
        System.out.println("method1");
    }
}

public class A implements AInterface {
    @Override
    public void method1() {
        System.out.println("method1 재정의!");
    }
}

public class Main {
    public static void main(String[] args) {
        AInterface a = new A();
        a.method1(); // method1 재정의!
    }
}

정적 메서드

정적 메서드도 자바 8에서 도입되었습니다. 정적 메서드는 구현 객체가 없어도 인터페이스만으로 호출할 수 있는 메서드입니다.

인터페이스의 정적 메서드는 static 키워드를 사용하여 선언합니다. 정적 메서드는 인터페이스 자체 내에서 구현하면 됩니다. 접근 제어자는 public을 가지며 생략 가능합니다.

public interface AInterface {

    static void method1() {
        System.out.println("method1");
    }
}

public class Main {
    public static void main(String[] args) {
        AInterface.method1(); // method1
    }
}

private 메서드

자바 9부터 private 접근 제어자를 가지는 메서드를 선언할 수 있습니다.

public interface AInterface {

    private static void staticMethod() {
        System.out.println("private static method");
    }

    private void defaultMethod() {
        System.out.println("private method");
    }

    default void call() {
        staticMethod();
        defaultMethod();
    }
}

public class A implements AInterface {
}

public class Main {
    public static void main(String[] args) {
        AInterface a = new A();
        a.call();
    }
}

인터페이스 상속

인터페이스도 다른 인터페이스를 상속할 수 있으며, 클래스와 다르게 다중 상속이 가능합니다.

public interface 인터페이스1 extends 인터페이스2, 인터페이스3 {
  ...
}


© 2023.06. by 고개

Powered by 고개