본문 바로가기
개발언어/Kotlin : 코틀린

코틀린 익히기 7 - 다양한 클래스와 인터페이스

by 개발자D 2023. 9. 27.

다양한 클래스와 인터페이스

코틀린의 다양한 클래스 - 추상 클래스, 데이터 클래스, 내부 클래스, 열거형 클래스, 실드 클래스

추상 클래스 abstract class : 추상 프로퍼티, 추상 메서드, 일반 프로퍼티, 일반 메서드 

abstract class 클래스명 ( /* 주생성자 */ ) {
	...
    abstract (val|var) 프로퍼티명 : 자료형
    
    abstract fun play()
}

추상 프로퍼티나 메서드가 하나라도 있다면 추상 클래스로 선언해야 합니다.

추상 프로퍼티와 메서드는 선언만 합니다. 프로퍼티의 경우 초기화 하지 않고, 메서드의 경우 본문을 구현하지 않습니다. 

추상 클래스와 추상 클래스의 프로퍼티, 메서드는 상속을 위해 open 키워드를 사용할 필요가 없습니다.

 


데이터 클래스 data class

data class 클래스명 ( /* 주생성자 */ ) {
	...
}

데이터 클래스는 데이터를 효과적으로 처리하기 위해 사용하는 클래스입니다. 일반 클래스와 달리 데이터 처리에 효과적인 메서드들이 정의되어 있습니다.

 

클래스명 (프로퍼티1=값1, 프로퍼티2=값2, ...)

data class의 인스턴스를 출력하면 프로퍼티를 보기 좋게 확인할 수 있습니다. 다만, 주 생성자에 선언된 멤버 변수만이 출력됩니다.

dataClassObject1.equals(dataClassObject2)

equals()를 통해 프로퍼티 값이 모두 일치하는지 비교할 수 있습니다. 다만, 주 생성자에 선언된 멤버 변수만을 비교합니다.

 

데이터 클래스의 조건

  • 주 생성자가 최소 하나 이상의 매개변수를 가져야 합니다.
  • 매개변수들은 모두 val이나 var 키워드로 지정되어야 합니다.
  • abstract, open, sealed, inner 키워드는 사용할 수 없습니다.

 

자동 생성 메서드

equals(), hashCode(), copy(), toString(), componentN() 

 

객체 디스트럭처링

객체가 가지고 있는 프로퍼티를 개별 변수로 분해하여 할당할 수 있습니다. 이를 객체 디스트럭처링이라고 부릅니다.

데이터 클래스는 기본적으로 객체 디스트럭처링을 지원합니다.

변수 이름과 관계없이 선언 순서대로 가져와 대입합니다.

 val|var  (프로퍼티1, 프로퍼티2) = 객체
// 프로퍼티1에는 객체.프로퍼티1 이 대입
// 프로퍼티2에는 객체.프로퍼티2 이 대입

 

값을 하나만 갖는 데이터 클래스는 객체 자체와 헷갈릴수 있기 때문에 디스트럭처링하지 않는 것이 권장됩니다.

 

componentN() 메서드를 사용해 객체 디스트럭처링 하는 방법도 있습니다.

val 프로퍼티1 = 객체.component1() // 프로퍼티1
val 프로퍼티2 = 객체.component2() // 프로퍼티2

내부 클래스

자바를 공부하셨다면 자바의 내부 클래스와 비교해봅시다. 자바를 모르신다면 건너뛰셔도 좋습니다.

자바의 내부 클래스

자바 쉽게 배우기 10 - 다양한 클래스와 인터페이스에서 배웠던 자바의 내부 클래스를 다시 살펴보겠습니다.

종류 위치 사용 목적
인스턴스 클래스 감싸는 클래스의 멤버변수 선언 자리
인스턴스 멤버처럼 취급
인스턴스 멤버와 관련된 작업에 사용
스태틱 클래스 감싸는 클래스의 멤버변수 선언 자리
스태틱 멤버처럼 취급
스태틱 멤버와 관련된 작업에 사용
지역 클래스 감싸는 클래스의 메서드, 초기화 블럭 자리 메서드나 초기화 블럭이 실행될 때 사용
익명 클래스 모든 위치 클래스를 만들고, 인스턴스를 생성하는 것을 간략화 하기 위한 용도로 사용
이름이 없기 때문에 한 번 사용되고 말 인스턴스를 만드는 데 사용

자바와 코틀린의 내부 클래스 비교하기

자바 코틀린
인스턴스 클래스 이너 클래스 
스태틱 클래스 중첩 클래스 
지역 클래스 지역 클래스 
익명 클래스 익명 객체

 

이너 클래스 inner class

class Outer { // 감싸는 클래스
	inner class Inner { // 이너 클래스
		이너클래스의멤버
        
		Outer클래스의멤버
	}
    
    Inner().이너클래스의멤버
}

fun main() {
	Outer().Inner().이너클래스의멤버
}

이너 클래스를 감싸는 클래스에서는 이너 클래스의 멤버를 이너클래스명().이너클래스의멤버로 사용할 수 있습니다.

이너 클래스 안에서는 감싸는 클래스의 멤버에 제약 없이 접근할 수 있습니다.

감싸는 클래스 바깥에서 이너클래스의 멤버를 사용할 때는 외부클래스명().이너클래스명().이너클래스의멤버로 사용해야 합니다.

 

중첩 클래스

class Outer { // 감싸는 클래스
	class Nested { // 중첩 클래스
	}
	Nested().중첩클래스의멤버
}

fun main() {
	Outer.Nested().중첩클래스의멤버
}

중첩 클래스를 감싸는 클래스에서는 중첩 클래스의 멤버를 중첩클래스명().중첩클래스의 멤버로 사용할 수 있습니다.

하지만, 중첩 클래스에서는 감싸는 클래스의 멤버에 접근할 수 없습니다.

접근하려는 멤버를 companion 객체로 만들어 주면 접근이 가능해집니다.

감싸는 클래스 바깥에서 중첩클래스의 멤버를 사용할 때는 외부클래스명.중첩클래스명().중첩클래스의멤버로 사용해야 합니다. 

 

지역 클래스

코틀린의 지역 클래스는 자바의 지역 클래스와 동일합니다. 클래스가 생성된 블록 {} 안에서만 유효합니다.

 

익명 객체

// 상속받거나 구현하고 싶을 때 

object: 상속받을 클래스() 혹은 구현할 인터페이스 {
	override ...
}

// 그냥 일회용으로 사용할 객체를 만들 때

object {}

익명 객체는 이름이 없고 일회성으로 사용되는 객체로 주로 한 번만 구현될 인터페이스를 오버라이딩하기 위해 사용됩니다.

 


열거형 클래스 enum class

 enum class 클래스명 ( /* 주생성자 */ ) {
	상수1[(값)], 상수2[(값)], 상수3[(값)], ...
	[; 프로퍼티 혹은 메서드]
}

열거형 클래스는 관련된 여러 상수를 한 데 모아 정의할 때 사용하는 클래스입니다.

선언된 상수들은 순서에 따라 0부터 1씩 증가하는 값을 가집니다. 선언된 상수들은 하나하나가 모두 객체입니다. 

순서를 그대로 사용하는 것이 아니라 상수 이름 옆에 괄호()를 붙여 값을 지정해 사용하는 것이 바람직합니다.

값을 지정해 주기 위해서는 생성자 매개변수가 필요합니다. 값과 같은 자료형으로 프로퍼티를 선언해 주면 됩니다. 

필요하다면 마지막 상수 끝에 ; 를 붙여 상수가 끝났음을 알리고 프로퍼티나 메서드를 선언할 수도 있습니다.

 

자동 생성 멤버

name : 상수 이름 자체

toString() : 이름을 가져오는 메서드

ordinal : 0부터 시작하는 순서 번호

 


실드 클래스 sealed class

sealed class 클래스명 {
    data class 클래스명( /* 주생성자 */ ): 실드클래스명()
    object 오브젝트명: 실드클래스명()
    [open] class 클래스명 ( /* 주생성자 */ ): 실드클래스명()
}

실드 클래스는 관련된 여러 자료형을 한 데 모아 사용하는 클래스입니다. 실드 클래스로는 객체를 생성할 수 없습니다.

같은 파일 안에만 실드 클래스를 상속받을 수 있습니다. 실드 클래스 내부에는 주로 data class나 object를 선언합니다.

파라미터가 필요할 경우 data class를, 필요하지 않은 경우 object를 사용합니다. 

 


인터페이스 interface : 추상 프로퍼티, 추상 메서드, 일반 메서드 

interface 인터페이스명 {
	...
    abstract (val|var) 프로퍼티명 : 자료형
    
    abstract fun play()
}

코틀린의 인터페이스에서는 추상 프로퍼티, 추상 메서드, 일반 메서드를 선언할 수 있습니다. 자바와 마찬가지로 디폴트 메서드의 선언이 가능합니다. 하지만, 코틀린에서는 default 키워드를 사용하지 않아도 괜찮습니다. 프로퍼티의 초기화는 불가능합니다.

 

인터페이스는 상속과 달리 다중 구현이 가능합니다.

 

 클래스와 인터페이스를 동시에 상속, 구현하거나, 여러 인터페이스를 구현했을 때 동일한 이름의 멤버를 가지고 있다면 이를 구분하기 위해 super<참조하고 싶은 클래스 혹은 인터페이스>.멤버 와 같은 형태로 사용합니다.

super<참조하고 싶은 클래스 혹은 인터페이스>.멤버

코틀린에서 사용하는 다양한 클래스와 인터페이스에 대해 알아보았습니다. 다양한 클래스들이 마련되어 있어 직접 구현하지 않아도 다양한 기능을 편하게 이용할 수 있습니다. 특히, 코틀린의 data class는 아주 유용합니다. 개발자가 데이터를 처리하기 위해 구현해야 했던 코드들을 자동으로 생성해주기 때문에 많은 시간을 절약할 수 있습니다. 다음 글에서는 제네릭에 대해 설명합니다.

 

코틀린 익히기 8 - 제네릭

제네릭 제네릭은 jdk 1.5부터 도입되었습니다. 타입을 미리 지정하지 않고 컴파일할 때 체크할 수 있도록 하는 기능입니다. 미리 타입을 지정해 두면 타입을 형변환하거나 체크해야 하는 번거로

devdharu.tistory.com