[ KOSTA 교육 20일차 ] final, abstract 클래스와 abstract 메소드, 다중상속, 다형성이란 무엇인가

junjun·2024년 5월 14일

KOSTA

목록 보기
17/48

제어자 ≠ 접근 제어자 (public, protected, default, private)

제어자 final

  • 변수
    • 상수, 값이 변할 수 없음.
    • 단, 인스턴스 변수의 경우 생성자를 통해 초기화 가능하다.
  • 메서드
  • 클래스

생성자를 이용한 final 멤버변수 초기화

  • final이 붙은 변수는 상수이므로,
    보통은 선언과 초기화를 동시에 하지만
    인스턴스 변수의 경우 생성자에서 초기화할 수 있다.
  • 이미 값을 넣어놨다면? ( 명시화 초기화 )
    생성자에서 초기화 불가능하다!

제어자 abstract

  • 클래스
    1. 인스턴스 생성이 불가능하다. ( new 못한다. )

    2. 클래스 내에 추상메서드가 선언되어 있음을 의미한다.

      • 아닌경우도 있음. ( 추상 메서드가 있을 수도 있다! 라는 뜻임 )

      • 완성되어 있는 추상클래스도 있다.
        다만, 인스턴스화 시키지 않기 위해 **abstract**를 사용하는 것이다.

      • 문제

      /**
       * abstract ( 추상, 미완성 )
       * - 클래스 : abstract 메서드가 있을 수~~도 있다.
       * - 메서드 : 바디가 없는 메서드.
       */
      
      public abstract class AbstractClassAndMethod {
      
      	public static void myPrint() {
      		System.out.println("Hi");
      	}
      	
      	public abstract void absPrint();
      	
      	public static void main(String[] args) {
      		myPrint();
      	}
      }
      • 실행이 되는가?
        • OK.

          Hi
      • abstract 제어자는, 해당 클래스를 인스턴스화 하는 것이 불가능한 것이지,
        클래스 자체가 로딩되지 않는 것이 아니다.
        - 따라서, abstract 클래스 내부의 static 메서드들은 호출 가능하다.

      즉, 다음과 같은 코드도 실행 가능하다.

      public class OuterClass {
      
      	public static void main(String[] args) {
      		AbstractClassAndMethod.myPrint();
      	}
      }
      • 실행 결과
        Hi
  • 메서드
    • 선언부만 작성하고 구현부는 작성하지 않은 추상메서드
    • **public abstract void absPrint();**
      • Body가 없다.
      • 이 안의 구현은? 해당 추상 클래스를 상속받은 클래스가 구현한다.

abstract 클래스를 왜 사용하는가?

어떨 때 abstract를 써야하는가?

  • 필요한 공통 기능이 미리 구현되어 있고,
    각자가 구현해야할 기능이 있는 경우.
  • 각자 구현 기능을
    자식 클래스에서 상황별로 각자 구현해야할 때. ( abstract로 선언된 메서드를 오버라이딩! )
  • 그런데, 인터페이스의 default 메서드가 있는데..
  • 추상클래스 = 공통 기능은 있음, 각 자식 클래스마다 구현을 해야하는 경우.
  • 인터페이스를 써도 된다..
  • 꼭 abstract 클래스를 사용하는 경우?
    • 하나의 클래스의 자식 클래스로 다 관리가 되어야 하는 경우
    • 관계가 중요한 경우

다중상속인 경우, 메서드를 어떻게 구별하는가?

  • ‘인터페이스명’.’메서드명’
    을 꼭 명시해주어야한다!!!!! ( 중요!!! )

부모가 추상클래스고 자식도 추상클래스라면,

반드시 추상메서드를 오버라이딩 할 필요 없다.

면접 질문 : 추상클래스 사용하는 이유

  • 구조적인 이유와 기능적인 이유로 나눌 수 있을 것 같습니다.
  • **구조적인 이유**
    PClass, CClass1, CClass2…
    - CClass1, CClass2 가 반드시 PClass의 자손으로 관리되어져야 할 때,
  • **기능적인 이유** 다른 클래스들이 PClass에서 제공되는 메서드를 공통으로 사용하되,
    일부 메서드는 자식 클래스 각자가 구현해야 하는 상황일 때 일반 비즈니스 메소드 사이 사이에
    각자 구현해야할 추상 메서드들이 포함되어야 할 때
    사용한다 생각합니다.
    • 이런 경우가 뭐가 있을까?
      • 결제 파트, 포인트 파트, 회원관리 파트
      • 회원실명 / 인증 파트 개발을 내가 할 때,
        **abstract void logWrite()** 함수를 만들어놓고,
        각자가 로그를 남기는 기능을 구현한다.
  • 그러면 기능적인 이유로 말씀하신 부분은
    interface의 default 메서드로 충분하지 않을까요?
사용하는 이유가 다르다 생각합니다.
default 메서드는 Java8에 람다와 스트림 API를 추가할 때,
기존 인터페이스들을 수정하지 않고, 기능을 추가해주기 위해
즉 이미 완성된 설계에 불가피한 수정이 필요할 때, 변경의 범위를 최소화하기 위해 도입한 기능입니다.

그렇지만, 추상클래스는
부모 자식 관계가 명확한 클래스들 사이에,
부모 클래스에서 정해진 방식대로 메소드를 사용하는 가이드라인을 제시할 때
사용할 수 있다 생각합니다.

인터페이스 ( Interface )

  • 추상 메서드들을 모아놓은 집합체.
    • 인터페이스를 상속받은 클래스들은 인터페이스의 추상메서드들을 무조건 구현해야 한다.
  • 인터페이스를 왜 사용하는가?
  • 공통의 메서드를 모아놓고, 사용하기 위함이다.
  • 구현체들은 해당 추상 메서드들을 각자 상황에 맞게 다르게 구현할 수 있습니다. ( 오버라이딩 )
    • 추상클래스를 상속받는 자손클래스는 추상메서드를 반드시 구현해야함.
  • 인터페이스의 상수는 모두
    **public static final** 이 붙는다, 이를 생략할 수 있다.
    인터페이스의 모든 메서드는
    **public abstract**가 붙는다, 이를 생략할 수 있다.,
    다같이 공통으로, 값이 변경되지 않는다.
    ( 일반 메서드가 추상 메서드를 호출하는 형태로 구현되어 있는 경우 )
    어떤 값이던 **double PI = 3.14** 이렇게 선언해도,
    그 앞에 자동적으로 접근제어자 + 제어자 **public static final** 이 붙는다.

추상클래스와 인터페이스

  • 추상 클래스가 인터페이스를 상속받은 경우,
    둘 다 추상이기 때문에 추상 클래스가 인터페이스를 오버라이딩할 필요 없다.

인터페이스

  • 일종의 추상클래스이다.
    추상 클래스(미완성 설계도)보다 추상화 정도가 높다.
  • 인스턴스를 생성할 수 없고, 클래스 작성에 도움을 줄 목적으로 사용된다.
  • 미리 정해진 규칙에 맞게 구현하도록 표준을 제시한다.
  • 미리 정해진 규칙에 맞게 구현하도록 표준을 제시한다.

다형성

  • 인터페이스를 배우고 나서 배우는 이유?
  • 캐스팅이다.
  • 양한 태의
    • 다양한 타입 형태를 접근할 수 있는 성질
  • 공통인 것 추출해서 인터페이스를 만들어라.
    • 각자 그 기능을 구현한다.
    • 실제 호출 시, 해당 클래스에 구현을 맡긴다. ( 오버라이딩 )

다형성은 왜 가능한가

다형성은 왜 필요한가

예시

  • 결제 ( Pay )를 만든다.
    • CashPay
    • CardPay
    • PointPay

자신의 클래스에 있는 메서드(부모에게도 있는 자식의 메서드)들을 제한적으로 사용하면서,

공통의 것을 해야할 때

오버라이딩된 메서드들만을 사용한다.

인터페이스의 장점

  • 다형성을 구현하기 편하다.
    • 부모클래스/인터페이스 타입 하나로, 여러 자식 타입에 접근할 수 있다.
  • 유연성을 얻을 수 있다.
    ( 부모 타입만 나타내보면, 다른 친구들을 다 상속해서, 그 타입을 사용하면 된다. )
    - 같은 메서드 호출에 대해, 각자 클래스들이 각자의 방식으로 동작하게할 수 있다.
  • 코드가 구조적으로 획일화되어, 관리가 용이하다.
    • 동일한 인터페이스를 구현하므로, 더 추상화되고 간결해진다.
    • 코드의 유연성
  • 확장이 용이하다.
    • 인터페이스를 상속받은 구현체를 만들면 된다.

배열 쓰지 말고, 유저 1000명 다루기.

~= 인터페이스 없이 공통적으로 해야하는 기능 만들기
( 개발자 각자만의 방식으로 알아서 공통 기능 메서드를 만든다. )

  • 다형성 ( Polymorphism )
    • 공통 기능을 빼서, 부모 클래스 / 인터페이스를 만들고,
      이 타입을 활용하여 자식 클래스 타입들을 가리킨다.

C-P 관계가 안되는 이유.

Child가 가리킬 수 있는 범위가 Parent 보다 넓기 때문이다.
Child의 메소드 중 일부가 유실된다. ( 접근 불가 )
사용할 수 없다.

인터페이스화, 구조적 프로그래밍,

책임을 호출하는 쪽으로 넘긴다.

/**

  • 다형성
  • 다양한 형태의 성질
  • 여러 타입에 접근할 수 있는 방법
  • 하나의 타입에 여러 객체를 대입할 수 있는 성질
  • 다형성이 뭐냐? PC! = Parent 타입으로 Child를 가리키는 것,
  • Child 인스턴스로 부모 타입의 객체에 접근하는 것.
  • 변수는 부모의 것이지만, 메서드는 자식의 메서드를 호출.
  • 공통 성질을 추상화하고, 해당 클래스를 상속받아
  • 각자의 성질을 갖도록 구현한다.
  • int n = 정수
  • Child c = new Child();
  • Parent p = new Parent();
  • Parent pc = new Child();
  • /

0개의 댓글