본문 바로가기

카테고리 없음

enum class sealed class and Companion object

enum (enumeration) : 이미 정의된 상수들로 이루어진 제한된 집합을 표현하는 특별한 클래스다.

  • “enum name”을 통해 enum class 엘리먼트들을 참조할 수 있다.
enum class SpartaClass{
  BASIC_CLASS, STANDARD_CLASS, CHALLENGE_CLASS
}

 

변수들을 선언한 상태보다 이와 같이 쓰면 가독성과 연관성을 한눈에 알아보기 쉬워지고 타입에 의한 열거형 이기 때문에 상수의 값이 같더라도 타입체크까지 해주기 때문에 좀 더 안전하게 변수 사용이 가능해진다.

-- companion object 엘리먼트들을 가지고 있다.

  • entries(Kotlin 1.9 버전부터 지원)
    • 모든 값을 리스트 형태로 반환한다. (기존 values() 함수가 존재)

valueOf 함수는 String 값을 enum의 상수 value와 같은 값이 있는지를 찾는 함수이다. 맞는 문자열 값이 있다면 해당 enum 의 인스턴스를 리턴한다.

 

values 함수는 enum에 선언된 모든 상수 인스턴스 List 컬렉션을 반환하여 loop를 돌릴 수 있도록 도와준다.

 

  • enumValues
    • 모든 값을 배열로 반환한다.
  • enumValueOf
    • input argument에 맞는 값을 반환한다(case-sensitive!)
  • name
    • 이름을 반환한다.
  • ordinal
    • 순서를 숫자로 반환한다.(0번째 index부터 시작)
    • !! 단, ordinal을 코드에서 사용하는 일이 없도록 하자(물론 잘못되었다는 것이 아님, 단 확장성, 유지보수성을 고려했을 때는 지양하도록 하자!)
  • data class와 마찬가지로 toString, equals, hashcode를 알아서 구현한다. 하지만 compareTo 또한 지원한다.
  • 각각의 enum value는 상태를 지닐 수 있다.

Sealed Class

  • 자기 자신이 추상 클래스이고, 자신을 상속받는 여러 서브 클래스들을 가질 수 있다.  enum클래스와 달리 상속을 지원하기 때문에, 다양한 동작 구현 가능
  • 상속받는 서브 클래스의 종류를 제한할 수 있음.
  • sealed 클래스의 서브 클래스들은 반드시 같은 파일 내에 선언되어야 합니다.
    • 단, sealed 클래스의 서브 클래스를 상속한 클래스들은 같은 파일 내에 없어도 됩니다.
    • interface, abstract 클래스를 사용하는 것과 거의 동일하다고 볼 수 있습니다.
    • sealed 클래스는 private 생성자만 갖게 됩니다.
    • 하위 클래스는 class, data class, object class로 정의할 수 있습니다.
  • “is” check을 통해 모든 가능한 하위 클래스를 확인해준다.
  • Sealed class는 abstract와 동일하다고 보면되지만 제한된 계층(restricted-hierarchy)를 지원한다.

 

  • Sealed vs Enum
    1. Enum은 상수 or 값들의 집합이다.
    2. Sealed는 subtype(하위 타입)의 집합이다. class 혹은 object로 만들 수 있다.
    3. Enum은 모든 값들이 동일한 필드/프로퍼티를 가져야 하지만, Sealed의 경우 원하는 형태대로 하위 타입을 커스터마이징 할 수 있다.
    4. 주로 Enum은 불변 값을 나타내는 경우, Sealed는 확장가능한 상태값을 나타내는 경우에 많이 사용된다.
    5. Enum은 상수 = 앱이 실행되면 메모리에 영원히 상주한다.
    6. Sealed 하위 타입의 경우 참조되지 않는 경우 GC에 의해 제거된다. 단 object로 선언되어 있으면 Enum과 마찬가지로 GC에 의해 제거되지 않는다.
      1. Enum 값이 몇만개가 되지 않는 이상 메모리 걱정은 할 필요가 없다.
      2. 오히려 sealed 하위 타입은 생성과 제거가 반복되기에 성능적으로 문제가 될 수 있지 않을까?
    7. when을 사용할 때 Enum은 단순한 상수비교이므로 “is” check을 통해 타입을 확인하는 sealed에 비해 빠르다. 단, 큰 차이는 없으니 걱정 nono.
      1. 아이스크림을 보고, ‘이것은 아이스크림인가?’ 바로 판단 가능
      2. 아이스크림을 보고, ‘이것은 딸기맛인가?’ → 맛을 봐야함(일단 느림)

 

 

companion object

클래스가 메모리에 올라갈 때, 동시에 companion object가 인스터스로서 힙에 올라간다 하여 '동반 객체'라고 한다

 

object키워드와의 연관성

object 키워드는 자바의 static 키워드와 new 키워드를 대신한다. 클래스 정보 적재와 객체 선언이 동시에 이루어진다

 

예를 들어 아래와 같이 object키워드로 Datasource를 선언하면, Datasource클래스를 정의함과 동시에 해당 인스턴스를 생성한다. 앞에 나온 Method Area, Heap Area에 동시에 정보를 적재한다는 뜻이다.

 

object Datasource {
  var baseUrl: String = "todolist-dev.leeyongin.com/"

  fun printBaseUrl) {
      println("baseUrl is : $baseUrl")
  }
}

object키워드와의 차이점

  • 클래스 내부에 있는 object를 굳힌 형태이다.
  • companion object 내부에 있는 변수, 메소드에 대한 접근을 더 자연스럽게 보이도록 한다
class DataSourceClass {
  object Datasource {
    var baseUrl: String = "todolist-dev.leeyongin.com/"

    fun printBaseUrl() {
        println("baseUrl is : $baseUrl")
    }
}
}

 

class DataSourceClass {
  companion object {
    var baseUrl: String = "todolist-dev.leeyongin.com/"

    fun printBaseUrl() {
        println("baseUrl is : $baseUrl")
    }
}
}

 

object 키워드를 사용하면 객체 내 static{} 에서 new를 이용한 객체생성과 변수 할당이 이루어진다.

public final class DataSourceClass {
  @Metadata(...중략...)
  public static final class Datasource {
        @NotNull
        private static String baseUrl;
        @NotNull
        public static final DataSourceClass.Datasource INSTANCE;

     

        static {
           DataSourceClass.Datasource var0 = new DataSourceClass.Datasource();
           INSTANCE = var0;
           baseUrl = "todolist-dev.leeyongin.com/";
        }
   }
}

 

companion object를 사용하면 아래와 같이 new를 이용한 객체생성과 변수 할당이 객체의 외부, 클래스의 내부에서 진행된다. 자바 개발이었다면 위의 패턴과 아래의 패턴을 구분해서 사용해야했겠지만 코틀린은 이걸 object와 companion object로 정형화했다.

public final class DataSourceClass {
  @NotNull
  private static String baseUrl = "todolist-dev.leeyongin.com/";
  @NotNull
  public static final DataSourceClass.Datasource Datasource = new DataSourceClass.Datasource((DefaultConstructorMarker)null);

  @Metadata()
  public static final class Datasource {
   
     public Datasource(DefaultConstructorMarker $constructor_marker) {
        this();
     }
  }
}

Static

 

Method Area

클래스에 대한 정보와 함께 클래스 변수(static variable)가 저장되는 곳이다.
런타임 상수 풀, 멤버 변수, 클래스 변수, 생성자 및 메소드를 저장한다.

Heap Area

반면 Heap Area는 동적으로 할당되는 정보가 있는 곳이다.

 

 

728x90