[코틀린 인 액션] CH4 클래스, 객체, 인터페이스

0

코틀린 인 액션

목록 보기
4/13
post-thumbnail

[코틀린 인 액션] CH4 클래스, 객체, 인터페이스

이 포스팅은 <<Kotlin in Action>>, 드미트리 제메로프 & 스베트라나 이사코바, 에이콘출판사(2017)을 읽고 개인 학습용으로 정리한 글입니다.

4.1 클래스 계층의 정의

4.1.1 코틀린 인터페이스

  • 코틀린 인터페이스 안에 추상 메서드 뿐만 아니라 구현이 있는 메서드 정의 가능

  • 인터페이스에는 아무런 상태(필드)도 들어갈 수 없다

  • 클래스는 인터페이스를 개수 제한 없이 구현 가능, 클래스는 오직 하나만 확장 가능

  • override 변경자 꼭 사용해야
    -> 상위 클래스에 있는 메서드와 시그니처가 같은 메서드를 우연히 하위 클래스에 선언 -> 컴파일 X

  • 한 클래스에서 시그니처가 같은 메서드가 들어있는 두 인터페이스를 함께 구현
    -> 두 메서드를 아우르는 구현을 하위 메서드에 직접 구현해야

  • 상위 타입의 구현을 호출할 때 super 사용
    -> super<<기반 클래스 이름>>

4.1.2 open, final, abstract 변경자

  • 취약한 기반 클래스(fragile base class) 문제
    -> 하위 클래스가 기반 클래스에 대해 가졌던 가정이 기반 클래스를 변경함으로써 깨져버린 경우 발생

  • 코틀린의 클래스와 메서드는 기본적으로 final(상속 불가능)
    -> 상속 허용하려면 클래스 앞에 open 변경자
    -> 오버라이드 허용하고 싶은 메서드/프로퍼티 앞에도 open 변경자

  • 오버라이드한 메서드는 기본적으로 열려있음
    -> 오버라이드하는 메서드의 구현을 하위 클래스에서 오버라이드 하지 못하게 금지하려면 final 명시해야

  • abstract로 선언한 추상 클래스는 인스턴스화 X

  • 추상 멤버는 항상 열려있다
    -> 추상 멤버 앞에 open 변경자 명시할 필요 X

  • 인터페이스 멤버의 경우 final, open, abstract 사용 X
    -> 인터페이스 멤버 항상 열려있음
    -> 인터페이스 멤버 final로 변경 X
    -> 인스턴스 멤버 본문 없으면 자동으로 추상 멤버

4.1.3 가시성 변경자: 기본적으로 공개

  • 아무 변경자도 없는 경우 선언 모두 public

  • 코틀린 internal 가시성 변경자
    -> 모듈 내부에서만 볼 수 있음
    -> 모듈: 한꺼번에 컴파일되는 코틀린 파일들
    -> 모듈의 구현에 대해 진정한 캡슐화 제공

  • 어떤 클래스의 기반 타입 목록에 들어있는 타입 가시성 -> 클래스 자신의 가시성보다 같거나 높아야
    제네릭 클래스의 타입 파라미터에 들어있는 타입의 가시성 -> 클래스 자신의 가시성보다 같거나 높아야

  • ex. public 클래스는 private 클래스를 자신의 기반 클래스로 가질 수 X

  • 메서드의 시그니처에 사용된 모든 타입의 가시성 -> 그 메서드의 가시성보다 같거나 높아야

  • ex. public 메서드는 private 타입을 인자로 가질 수 X

  • 자바에서는 클래스를 private으로 만들 수 X -> 내부적으로 패키지-전용 클래스로 컴파일
    자바에는 internal 변경자에 딱 맞는 가시성 없음 -> 내부적으로 public으로 컴파일
    -> 코틀린에서 접근할 수 없는 대상을 자바에서 접근할 수 있는 경우 생김

4.1.4 내부 클래스와 중첩된 클래스: 기본적으로 중첩 클래스

  • 코틀린의 중첩 클래스(nested class)는 바깥쪽 클래스 인스턴스에 대한 접근 권한 X
    -> inner 변경자를 붙여 내부 클래스로 변경해야

4.1.5 봉인된 클래스: 클래스 계층 정의 시 계층 확장 제한

  • 상위 클래스에 sealed 변경자를 붙이면 그 상위 클래스를 상속한 하위 클래스 정의 제한 가능

  • sealed 클래스의 하위 클래스를 정의할 때는 반드시 상위 클래스 안에 중첩시켜야

  • sealed 클래스에 속한 값에 대해 디폴트 분기를 포함하지 않고 when 식 사용
    -> 나중에 sealed 클래스의 상속 계층에 새로운 하위 클래스 추가하면 when식 컴파일되지 X

4.2 뻔하지 않은 생성자와 프로퍼티를 갖는 클래스 선언

4.2.1 클래스 초기화: 주 생성자와 초기화 블록

  • 초기화 블록: 클래스의 객체가 생성될 때 실행될 초기화 코드 들어감

  • 초기화 블록은 주 생성자와 함께 사용됨

  • 필요하다면 클래스 안에 여러 초기화 블록 선언 가능

  • 클래스에 기반 클래스가 있다면 주생성자에서 기반 클래스의 생성자를 호출해야

  • 클래스 정의에 있는 상위 클래스 및 인터페이스 목록에서
    이름 뒤에 괄호가 있으면 기반 클래스, 없으면 기반 인터페이스

4.2.2 부 생성자: 상위 클래스를 다른 방식으로

  • 하위 클래스에 주생성자가 없으면 모든 부 생성자는 반드시 상위 클래스를 초기화하거나 다른 생성자에게 생성을 위임해야

4.2.3 인터페이스에 선언된 프로퍼티 구현

  • 인터페이스에서 추상 프로퍼티를 선언하는 경우
    -> 하위 클래스는 추상 프로퍼티를 반드시 오버라이드해야

  • 인터페이스에서 세터와 게터가 있는 프로퍼티를 선언하는 경우
    -> 게터와 세터는 뒷받침하는 필드를 참조할 수 X

4.2.4 게터와 세터에서 뒷받침하는 필드에 접근

  • 접근자 본문에서 field라는 특별한 식별자를 통해 뒷받침하는 필드에 접근 가능

4.2.5 접근자의 가시성 변경

4.3 컴파일러가 생성한 메서드: 데이터 클래스와 클래스 위임

4.3.1 모든 클래스가 정의해야 하는 메서드

문자열 표현: toString()

객체의 동등성: equals()

  • 코틀린에서 == 연산자는 참조 동일성을 검사하지 않고 객체 동등성을 검사
    -> ==연산은 equals를 호출하는 식으로 컴파일
    -> 참조 비교는 === 연산자 사용

  • a==b
    a?.equals(B)?:(b==null)

해시 컨테이너: hashCode()

  • JVM 언어의 규칙: equals()가 true를 반환하는 두 객체는 반드시 같은 hashCode()를 반환해야

4.3.2 데이터 클래스: 모든 클래스가 정의해야 하는 메서드 자동 생성

  • 주 생성자 밖에 정의된 프로퍼티는 equals나 hashCode를 계산할 때 고려 대상X

데이터 클래스의 불변성: copy()

  • HashMap 등의 컨테이너에 데이터 클래스나 객체를 담는 경우 불변성 필수적

  • copy메서드는 객체를 복사하면서 일부 프로퍼티를 바꿀 수 있게 해줌
    -> 복사본은 원본과 다른 생명주기를 가짐
    -> 원본을 참조하는 다른 부분에 전혀 영향X

4.3.3 클래스 위임: by 키워드 사용

  • 데코레이터(Decorator) 패턴: 상속을 허용하지 않는 클래스(기존 클래스) 대신 사용할 수 있는 새로운 클래스(데코레이터) 만들기
    -> 기존 클래스와 같은 인터페이스를 데코레이터가 제공
    -> 기존 클래스를 데코레이터 내부에 필드로 유지

  • 새로 정의해야 하는 기능은 데코레이터의 메서드에 새로 정의
    기존 기능이 그대로 필요한 부분은 데코레이터의 메서드가 기존 클래스의 메서드에게 요청 전달(forwarding)

  • by 키워드: 인터페이스에 대한 구현을 다른 객체에 위임 중이라는 사실 명시 가능

4.4 object 키워드: 클래스 선언과 인스턴스 생성

  • object 키워드: 모든 경우 클래스를 정의하는 동시에 인스턴스 생성

4.4.1 객체 선언: 싱글턴을 쉽게 만들기

  • 자바의 싱글턴 패턴: 클래스의 생성자를 private으로 제한하고 정적인(static) 필드에 그 클래스의 유일한 객체 저장

  • 코틀린의 싱글턴 패턴: 객체 선언
    -> 클래스의 선언과 그 클래스에 속한 단일 인스턴스의 선언을 합친 선언

  • 객체 선언에 생성자(주 생성자와 부 생성자 모두)는 쓸 수 X
    -> 싱글턴 객체는 객체 선언문이 있는 위치에서 생성자 호출 없이 즉시 만들어짐

  • 객체 선언도 클래스나 인터페이스 상속 가능

  • 클래스 안에서 객체 선언 가능 -> 그런 객체도 인스턴스는 하나 뿐
    -> 바깥 클래스의 인스턴스마다 중첩 객체 선언에 해당하는 인스턴스가 하나씩 따로 생기지 X

4.4.2 동반 객체: 팩토리 메서드와 정적 멤버가 들어갈 장소

  • 동반 객체의 프로퍼티나 메서드에 접근하려면 그 동반 객체가 정의된 클래스 이름 사용

  • 동반 객체는 자신을 둘러싼 클래스의 모든 private 멤버에 접근 가능

  • 동반 객체 멤버를 하위 크래스에서 오버라이드할 수 X

4.4.3 동반 객체를 일반 객체처럼 사용

동반 객체 확장

  • 클래스의 동반 객체 안에 함수 정의 -> 클래스에 대해 호출할 수 있는 확장 함수

  • ex. C라는 클래스 안에 동반 객체가 있고 그 객체(C.Companion)안에 func를 정의하면
    외부에서는 func()를 C.func()로 호출 가능

  • 동반 객체에 대한 확장 함수를 작성할 수 있으려면 원래 클래스에 동반 객체를 꼭 선언해야
    -> 빈 객체라도 동반 객체가 꼭 있어야

4.4.4 객체 식: 무명 내부 클래스를 다른 방식으로 작성

  • 객체 선언과 달리 무명 객체는 싱글턴 X
    -> 객체 식이 쓰일 때마다 새로운 인스턴스 생성됨

  • 무명 객체 안에 여러 메서드를 오버라이드해야 하는 경우에 훨씬 유용

profile
Be able to be vulnerable, in search of truth

0개의 댓글