[Kotlin] Class

sundays·2022년 9월 4일
0

kotlin

목록 보기
7/19

1. 추상 클래스 (Abstract Class)

  • 구현 클래스에서 가져야할 명세를 정의한 클래스
  • abstract 라는 키워드와 함께 선언하며 추상클래스는 객체 생성 안됨
  • 구체적이지 않은 것을 나타내기 때문에 하위 파생 클래스에서 구체적으로 구현
  • open 키워드를 사용하지 않고도 파생 클래스 작성 가능
// 추상 클래스, 주 생성자에는 비 추상 프로퍼티 선언의 매개변수 3개가 있음
abstract class Vehicle(val name: String, val color: String, val weight: Double) {

    // 추상 프로퍼티 (반드시 하위 클래스에서 재정의해 초기화해야 함)
    abstract var maxSpeed: Double

    // 일반 프로퍼티 (초기 값인 상태를 저장할 수 있음)
    var year = "2018"

    // 추상 메서드 (반드시 하위 클래스에서 구현해야 함)
    abstract fun start()
    abstract fun stop()

    // 일반 메서드
    fun displaySpecs() {
        println("Name: $name, Color: $color, 
        	Weight: $weight, Year: $year, Max Speed: $maxSpeed")
    }
}

2. Interface

interface Pet {
    var category: String // abstract 키워드가 없어도 기본은 추상 프로퍼티
    fun feeding() // 마찬가지로 추상 메서드
    fun patting() { // 일반 메서드: 구현부를 포함하면 일반적인 메서드로 기본이 됨
        println("Keep patting!") // 구현부
    }
}
  • 현실세계의 계약서 역할
  • 다른 언어와는 다르게 기본적인 구현 내용이 포함될 수 있다
    • java8에서 default 키워드로 구현내용을 생성가능
  • 상속한 하위 클래스에서는 override 를 사용해 해당 메서드를 구현
  • 인터페이스에서는 프로퍼티에 값을 저장 할 수 없지만 val 로 선언된 프로퍼티는 getter를 통해 필요한 내용을 구현가능
  • 클래스가 아니므로 다양한 인터페이스로부터 클래스 구현가능 (다중상속)
interface Bird {
	val wings: Int
	fun fly()
	fun jump() = println("bird jump!")
}
interface Horse {
	val maxSpeed: Int
	fun run()
	fun jump() = println("jump!, max speed: $maxSpeed")
}
class Pegasus: Bird, Horse {
	override val wings: Int = 2
	override val maxSpeed: Int = 100
	override fun fly() = println("Fly!")
	override fun run() = println("Run!")
	override fun jump() {
		super<Horse>.jump()
		println("and Jump!")
	}
}

3. DTO (Data Transfer Object)

data class Customer(var name: String, var email: String)
  • 자바에서 POJO(Plaint Old Java Object) 에 해당
  • 구현 로직은 없고 순수한 데이터 객체를 표현
  • getter/setter 를 포함
  • 주 생성자는 최소한 하나의 매개변수를 가져야 한다
  • 주 생성자는 모든 매개변수는 val, var 로 지정된 프로퍼티여야 한다
  • 데이터 클래스는 abstract, open, sealed, inner 키워드를 사용할 수 없다
  • 자동 생성 메서드들
    • equals() : 고유값은 다르지만 의미값이 같을 때 사용
    • hashCode() : 객체를 구별하기 위한 고유한 정수값 생성
    • copy() : 빌더 없이 특정 프로퍼티만 변경해서 객체 복사하기
    • toString() : 데이터 객체를 읽기 편한 문자열로 반환하기
    • componentN() : 객체의 선언부 구조를 분해하기 위해 프로퍼티에 상응하는 메서드

예시

// 간단한 로직을 포함하려면 init 블록이나 부생성자에 데이터를 위한 간단한 로직을 포함한다
data class Customer(val name: String, val email : String) {
	val job : String = "unknown"
    constructor(name: String, email :String, _job:String) : String(name :email) {
    job = _job
    }
    
    init {
    	// 간단한 로직 포함
    }
}

equals()와 hashCode() 예시

val cus1 = Customer("Sean", "sean@email.com")
val cus2 = Customer("Sean", "sean@email.com")
..
println(cus1 == cus2) // true
println(cus1.equals(cus2)) // true
println(${cus1.hashCode()}, ${cus2.hashCode()}) // 동일

copy() 예시

val cus3 = cus1.copy(name = "Alice") // name 만 변경
println(cus1.toString()) // Customer(name=Sean, email=sean@email.com)
println(cus3.toString()) //Customer(name=Alice, email=sean@email.com)

3.1. 객체 디스트럭처링(destructuring)

// 객체가 가진 프로퍼티를 개별 변수들로 분해
val (name, email) = cus1
println("name = $name, email = $email")

// 특정 프로퍼티를 가져올 필요가 없는 경우
val (_, email) = cus1 // 첫 번째 프로퍼티 제외

4. 내부 클래스

자바코틀린
정적 클래스 (Static Class)중첩 클래스(Nested Class) : 객체 생성 없이 사용 가능
멤버 클래스 (Member Class)이너 클래스(Inner Class) : 필드나 메서드와 연동하는 내부클래스, inner 키워드 필수
지역 클래스 (Local Class)지역 클래스(Local Class) : 클래스의 선언이 블록에 있다면 지역 클래스
익명 클래스 (Anonymous Class익명 객체(Anonymous Object) : 이름이 없고 주로 일회용 객체를 사용하기 위해 object 키워드를 통해 선언

4.1. Inner class 와 Nested Class

사용법이 자바와 많이 달라서 주의해야 한다.

// 1. Inner Class
class A {
	inner class B { // inner 키워드 필수
    	// 외부 클래스 A 필드에 접근가능
    }
}

// 2. Nested Class
class A {
	class B {
    	// 키워드를 사용하지 않으면 중첩 클래스이며 정적 클래스처럼 사용합니다
        // 외부 클래스 A필드에 접근 불가
    }
}

Nested 또는 Inner 클래스가 아닌 경우 companion object를 이용해서 바깥 클래스에 접근 할 수 있습니다.

  • Nested Class
    • 정적 클래스 처럼 사용
  • Inner Class
    • 이너 클래스는 바깥 클래스의 멤버들에게 접근 가능
    • 바깥 클래스의 private 멤버도 접근이 가능

4.2. Local Class

  • 특정 메서드 블록, init 블록과 같이 블록 범위에만 유효
  • 블록 범위를 벗어나면 사용 불가

4.3. Anonymous Class

  • 익명 클래스
  • object 키워드를 사용하는 익명 객체로 일회성 객체를 생성ㅇ해 사용한다

4.4. Sealed Class

  • 실드란 '봉인된' 이라는 의미로 무언가 안전하게 보관하기 위해 묶어두는 것
  • sealed 키워드를 class와 함께 사용
  • 실드 클래스 그 자체로는 추상 클래스와 같기 때문에 객체를 만들 수는 없다
  • private 의 생성자만 허용 가능
  • 같은 파일 안에서는 상속가능 다른 파일에서는 상속 불가
  • 블록 안에 선언되는 클래스는 상속이 필요한 경우 open 키워드로 선언
// 1. 실드 클래스 선언 방법
sealed class Result {
    open class Success(val message: String): Result()
    class Error(val code: Int, val message: String): Result()
}

class Status: Result() // 실드 클래스 상속은 같은 파일내에서만 가능
class Inside: Result.Success("Status") // 내부 클래스 상속

// 2. 실드 클래스 선언 방법
sealed class Result

open class Success(val message:String) :Result()
class Error(val code:Int, val message: String) :Result()

class Status: Result() // 실드 클래스 상속은 같은 파일내에서만 가능
class Inside: Success("Status") // 내부 클래스 상속

- when 구문을 작성시 if-else 문을 사용하지 않는다

// 상태를 검사하기 위한 함수
fun eval(result: Result): String = when(result) {
    is Status -> "In progress"
    is Result.Success -> result.message
    is Result.Error -> result.message
    // 모든 조건을 가지므로 else 가 필요없음
}

4.5. Enum Class

  • 여러개의 상수를 선언하여 조건에 따로 선택할 수 있는 특수 클래스
  • 실드 클래스와 거이 비슷하지만 다양한 자료형을 다루지 못함

예시

enum class Direction {
    NORTH, SOUTH, WEST, EAST
}

각 상수는 Direction 클래스의 객체로 취급되고 콤마로 구분

enum class DayOfWeek(val num:Int) {
	MONDAY(1), TUESDAY(2), WENDSDAY(3), THURSDAY(4), FRIDAY(5), SATURDAY(6), SUNDAY(7)
}

메서드가 포함되는 경우

enum class Color(val r:Int, val g:Int, val b:Int) {
	RED(255, 0, 0), BLUE(0, 0, 255), YELLOW(255,255,0);
    
    fun rgb = (r * 256 + g) * 256 + b // 메서드 포함 가능
}

fun main() {
	println(Color.BLUE.rgb())
}

4.6. Annotation Class

  • 부가 정보를 추가하는 기능 역할
  • @ 기호화 함께 컴파일러 프로그램 실행 기간에서 사전 처리를 위해 주로 사용
  • 속성
    • @Target : 애노테이션이 지정되어 사용할 종류(클래스, 함수, 프로퍼티 등)를 정의
    • @Retention : 애노테이션을 컴파일된 클래스 파일에 저장할 것인지 실행 시간에
      반영할 것인지 결정
    • @Repeatable : 애노테이션을 같은 요소에 여러 번 사용 가능하게 할지를 결정
    • @MustBeDocumented : 애노테이션이 API의 일부분으로 문서화하기 위해 사용

5. 연산자 오버로딩

  • 연산자에 여러 가지 다른 의미의 작동을 부여
  • 코틀린에서는 특정 연산자의 역할을 함수로 정의
  • operator 키워드를 사용해 정의

5.1. 수식 연산자

표현식함수 의미
a+ba.plus(b)
a-ba.minus(b)
a*ba.times(b)
a/ba.div(b)
a%ba.rem(b)
a..ba.rangeTo(b)

5.2. 호출 연산자

  • invoke operator 함수 호출을 돕는데 사용한다

5.3. 인덱스 연산자

  • getter/setter 를 다루기 위한 대괄호 연산자 제공
표현식함수 의미
a[i]a.get(i)
a[i,j]a.get(i,j)
a[1_1,...,i_n]a.get(i_1,...i_n)
a[i] =ba.set(i, b)
a[i,j] =ba.set(i,j,b)
a[i_1,...,i_n] = ba.set(i_1,...,i_n, b)

5.4. 단일연산자

표현식함수 의미
+aa.unaryPlus()
-aa.unaryMinus()
!aa.not()

5.5. 포함 범위 연산자

표현식함수 의미
a in bb.contains(a)
a in b!b.contains(a)

5.6. 할당 연산자

표현식함수 의미
a += ba.plusAssign(b)
a -= ba.minusAssign(b)
a *= ba.timesAssign(b)
a /= ba.divAssign(b)
a %= ba.remAssign(b)

5.7. 동등성 연산자

표현식함수 의미
a == ba?.equals(b) ?: (b === null)
a != b!(a?.equals(b) ?: (b === null))

5.8. 비교 연산자

표현식함수 의미
a > ba.compareTo(b) > 0
a < ba.compareTo(b) < 0
a >= ba.compareTo(b) >= 0
a <= ba.compareTo(b) <= 0

Reference

  • 코틀린 프로그래밍 - 황영덕
profile
develop life

0개의 댓글