Java

Java(8) 추상클래스와 인터페이스

hyomee2 2024. 8. 8. 16:44

1. 추상 클래스

(1) 추상클래스란?

: 추상 메소드를 0개 이상 포함하는 클래스 (추상 메소드가 없어도 추상 클래스로 만들 수 있다.)

- 추상 메소드: 메소드의 기능이 없고 헤더부만 존재하는 불완전한 메소드

- 추상 메소드가 있으면 반드시 추상 클래스로 만들어야 한다.

- 스스로 자신의 생성자를 활용한 인스턴스 생성 불가(불완전한 클래스)

 -> 추상클래스는 상속을 활용해 하위 클래스 타입의 인스턴스를 이용해서 인스턴스 생성해야 한다.

// 추상 클래스 선언
public abstract class Product {
    // 추상 클래스는 필드를 가질 수 있다.
    private int nonStaticField;
    private static int staticField;

    // 추상 클래스는 생성자를 가질 수 있지만 직접적으로 인스턴스를 생성할 수는 없다.
    public Product() {}

    // 추상 클래스는 일반적인 메소드를 가질 수 있다.
    public void nonStaticMethod() {
        System.out.println("Product 클래스의 nonStaticMethod");
    }

    public static void staticMethod() {
        System.out.println("Product 클래스의 staticMethod");
    }

    // 추상 메소드 작성
    public abstract void abstMethod();
}


// 자식 클래스 선언
// 추상 클래스를 상속 받을 경우엔 추상 메소드를 반드시 오버라이딩 해야 한다. (오버라이딩 강제화) 
public class SmartPhone extends Product {
    @Override
    public void abstMethod() {
        System.out.println("Product 클래스의 abstMethod 오버라이딩 한 메소드 호출");
    }

    /* 추가적 메소드 작성 */
    public void printSmartPhone() {
        System.out.println("SmartPhone 클래스의 printSmartPhone 메소드 호출");
    }
}
public class Application {
    public static void main(String[] args) {

        /* 추상 클래스는 인스턴스 생성 불가 */
        // Product product = new Product();
        SmartPhone smartPhone = new SmartPhone();

        System.out.println(smartPhone instanceof SmartPhone);
        System.out.println(smartPhone instanceof Product);

        /* 다형성을 적용해서 추상 클래스를 레퍼런스 타입으로 사용할 수 있다. */
        Product product = new SmartPhone();
        product.abstMethod();

        product.nonStaticMethod();
        Product.staticMethod();

    }
}

 

(2) 추상 클래스를 사용하는 이유

- 추상클래스는 스스로 인스턴스를 만들지는 못하지만 다형성 적용을 위한 부모 타입 역할을 해낼 수 있다.

- 추상 메소드를 통해 자식 클래스에 오버라이딩에 대한 강제성 부여 가능

 (추상 클래스를 상속받는 자식 클래스는 반드시 추상 메소드를 오버라이딩 해야하기 때문)

 -> 필수 기능을 정의해 일관된 인터페이스(동일 기능) 제공에 있어 도움이 된다.

 

 

2. 인터페이스

(1) 인터페이스란?

:  추상 메소드와 상수 필드만 가질 수 있는 클래스의 변형체

- 상수 필드, 추상메소드만 작성 가능하다. (따라서 모든 필드는 묵시적으로 public static final )

- 생성자를 가질 수 없다.

- 구현부가 있는 non-static 메소드를 가질 수 없다.

- default 키워드를 사용하면 non-static 메소드 작성 가능. default 메소드는 완성되어 있으므로 오버라이딩이 강제화되지 않는다.

- 인터페이스는 인터페이스를 상속할 수 있다. (이 때는 extends 사용)

  ㄴ 클래스 extends 클래스 (단일 상속)

       클래스 implements 인터페이스1, 인터페이스2 (다중 상속)

       인터페이스 extends 인터페이스1, 인터페이스2 (다중 상속)

 

public interface InterProduct extends java.io.Serializable {
    // 인터페이스는 상수 필드만 작성 가능
     public static final int MAX_NUM = 100;
     int MIN_NUM = 0;

    // 인터페이스는 생성자를 가질 수 없다.
    // public InterProduct(){}

    // 인터페이스는 구현부가 있는 non-static 메소드를 가질 수 없다.
    // public void nonStaticMethod(){}

    // 추상 메소드만 작성이 가능하다.
    public abstract void nonStaticMethod();
    void abstMethod();

    // static 메소드 작성 가능하다. (JDK 1.8 추가) */
    public static void staticMethod(){
        System.out.println("InterProduct 인터페이스의 staticMethod 호출");
    }
    
    // default 키워드를 사용하면 non-static 메소드도 작성 가능하다. (JDK 1.8 추가)
    // default 메소드는 완성 되어 있으므로 오버라이딩이 강제화 되지 않는다.
    // 일반적으로는 {} 만 작성하고 내용을 비워놓는다.
    public default void defaultMethod() {
        System.out.println("InterProduct 인터페이스의 defaultMethod 호출");
    }
}


public class Product extends Object implements InterProduct, java.io.Serializable {
    // InterProduct의 추상 메소드는 반드시 구현해야 한다. (오버라이딩 강제화) */
    @Override
    public void nonStaticMethod() {
        System.out.println("InterProduct의 nonStaticMethod 오버라이딩한 메소드 호출");
    }

    @Override
    public void abstMethod() {
        System.out.println("InterProduct의 abstMethod 오버라이딩한 메소드 호출");
    }

    // static 메소드는 오버라이딩 할 수 없다.

    // default 메소드는 오버라이딩이 강제화 되지 않는다.(선택적 오버라이딩)
    // default 키워드는 인터페이스 내에서 사용하는 키워드이고, 오버라이딩 시에는 제거한다.
    @Override
    public /* default */ void defaultMethod() {
        System.out.println("InterProduct의 defaultMethod 오버라이딩한 메소드 호출");
    }
}
public class Application {
    public static void main(String[] args) {
        // InterProduct interProduct = new InterProduct();

        // 다형성을 이용하여 레퍼런스 타입으로 사용 
        InterProduct interProduct = new Product();

        // 오버라이딩 된 메소드 호출 
        interProduct.abstMethod();
        interProduct.nonStaticMethod();
        interProduct.defaultMethod();   // default이지만 오버라이딩 했음

        // static 메소드 호출
        InterProduct.staticMethod();

        // 상수 필드
        System.out.println(InterProduct.MAX_NUM);
        System.out.println(InterProduct.MIN_NUM);
    }
}

 

(2) 인터페이스를 사용하는 이유

- 인터페이스는 일종의 추상 클래스라고 할 수 있는데,

추상클래스처럼 추상메서드를 갖지만, 추상 클래스보다 추상화 정도가 높아서 추상 메서드와 상수만을 멤버로 가질 수 있다.

추상 클래스를 미완성 설계도라고 하면 인터페이스는 밑그림만 그려져 있는 기본 설계도라고 할 수 있다.

전체적인 틀을 짜준 후 실제 구현 클래스에서 메서드 내용 부분을 채워넣어 구현을 해주는 것이다.

- 모든 클래스는 하나의 부모 클래스 외에도 여러 개의 인터페이스 구현 가능

 

 

3. 추상클래스와 인터페이스

구분 추상 클래스 인터페이스
상속 가능 범위 단일 상속 다중 상속
키워드 extends implements
자체 인스턴스 생성 생성 불가 생성 불가
다형성 적용 시
상위 타입 활용 가능 유무
가능 가능