[Kotlin] 3장. 코틀린 문법 - 함수, 클래스, NULL

Hwichan Ji·2020년 12월 18일
0

Kotlin

목록 보기
3/11
post-thumbnail

이것이 안드로이드다 with 코틀린(고돈호 지음) 으로 공부한 내용을 정리한 글입니다.

함수

함수의 정의

함수는fun 키워드로 정의하며 파라미터와 반환 값이 없을 수도 있습니다.

fun 함수명(파라미터1: 타입, 파라미터2: 타입, ··· ): 반환 타입 {
    return}

함수의 사용

함수를 사용하기 위해선 함수 이름 뒤에 괄호를 붙여야 합니다.

함수명(인자)

ex) var sqr = square(30)

함수 파라미터의 정의

코틀린에서 함수 파라미터를 통해 입력되는 모든 값은 변하지 않는 Immutable 입니다. 따라서 코틀린에서의 함수 파라미터는 모두 val이 생략된 형태라고 생각할 수 있습니다.

fun 함수명((val 생략) 파라미터 이름: 타입)

파라미터가 val인 이유

  • 코틀린에서 매개 변수는 pass by value 로 전달되는데, var이 허용될 경우 매개 변수를 pass by reference (런타임에 비용이 많이 듦)로 전달된다고 생각할 수 있기 때문에 혼동을 방지
  • 매개변수를 변경하는 것이 좋은 코딩 스타일이 아니라서
  • 출처

파라미터의 기본값

파라미터는 정의할 때 =을 사용해서 기본값을 설정할 수 있습니다.

fun 함수명(파라미터 이름: 타입 = 기본값)

기본값이 설정되지 않은 파라미터는 함수를 사용할 때 반드시 인자로 값을 받아야 하지만, 기본값이 설정된 파라미터는 인자로 값을 받지 못하면 자동으로 기본값으로 설정됩니다.

파라미터 이름으로 값을 입력하기

함수를 사용할 때, 파라미터의 순서와 상관 없이 정의된 파라미터 이름을 지정하여 직접 값을 입력할 수 있습니다.

fun newFunction(name: String, age: Int = 29, weight: Double) {
    // ...
}

newFunction("Michael", weight = 67.5)

클래스와 설계

클래스의 기본 구조

class 클래스명 {
    var 변수
    fun 함수() {
        // ...
    }
}

클래스의 생성

클래스에 생성자를 정의하지 않은 채 인스턴스를 생성할 경우 기본 생성자가 호출되는데, 기본 생성자는 파라미터가 아무것도 없는 빈 코드 블록입니다.

class NewClass {
    init {
    
    }
}

Primary Constructor

Primary Constructor는 마치 클래스의 헤더처럼 사용할 수 있으며 constructor 키워드를 사용하여 정의합니다. Primary Constructor 는 클래스 당 하나만 존재할 수 있습니다.

class NewClass constructor(value: String) {
    // ...
}

Primary Constructor 에 접근 제한자나 특정 옵션이 없다면 constructor 키워드를 생략할 수 있습니다.

class NewClass (생략)(value: String) {
    // ...
}

Primary Constructor 가 헤더에 작성되기 때문에 생성자 옆이 아닌 init 블록에 코드를 작성하여 자신의 코드 블록처럼 사용할 수 있습니다. 만약 파라미터가 존재한다면 해당 파라미터는 init 블록에서 접근할 수 있습니다.

class NewClass(value: String) {
    init {
        // ...
    }
}

Secondary Constructor

Secondary Constructor는 함수처럼 작성합니다. Secondary Constructor 는 한 클래스 내에서 여러 개 존재할 수 있습니다.

class NewClass {
    constructor (value: String) {
        // ...
    }
}

Primary Constructor 가 존재한다면 Secondary Constructor 는 반드시 Primary Constructor 에게 생성을 위임해야 합니다. 이때 this 키워드를 이용합니다.

class NewClass (var value:String) {
    constructor(value:String, age:Int) : this(value) {
  
    }
}

클래스의 사용

코틀린에서 클래스 인스턴스는 new 키워드 없이 생성자를 호출하여 생성합니다.

클래스명(인자)

ex) var mClass = NewClass("value")

클래스 내부의 변수나 함수는 .을 통해 접근할 수 있습니다.

mClass.print()

Companion Object

companion object는 클래스를 인스턴스화 하지 않아도 사용할 수 있는 코드 블록입니다. companion object 외부의 변수나 함수는 인스턴스화 없이 사용할 수 없습니다.

class NewClass {
    companion object {
        // ...
    }
}

데이터 클래스

코틀린은 간단한 값의 저장 용도로 data class를 따로 제공합니다. data class는 일반적인 클래스의 생성자처럼 파라미터를 정의할 수 있는데, var 또는 val을 명시하여 변수인지 상수인지를 구분해야 합니다.

data class 클래스명 (val 파라미터1: 타입, var 파라미터2: 타입)

데이터 클래스의 정의와 생성

데이터 클래스는 일반 클래스와 동일하게 생성합니다. 일반 클래스는 toString() 메서드를 호출하면 인스턴스의 주소값을 반환하지만, 데이터 클래스는 값을 반환하기 때문에 실제 값을 모니터링할 때 좋습니다.

data class DataUser (var name: String, var age: Int)

copy() 메서드 지원

var user = DataUser("Michael", 21)
var newData = user.copy()

클래스의 상속과 확장

클래스의 상속

상속 대상이 되는 부모 클래스는 open 키워드로 만들어야만 상속할 수 있습니다.

open class 상속될 부모 클래스(파라미터1: 타입) {

}

class 자식 클래스 (파라미터2: 타입, 파라미터3: 타입) : 부모 클래스(파리미터2) {

}

부모 클래스에 Secondary Constructor 가 있다면, 자식 클래스의 Secondary Constructor 에서 super 키워드로 부모 클래스에 전달할 수 있습니다.

class CustomView : View(생략) {
    constructor(ctx: Context): super(ctx)
}

부모 클래스의 프로퍼티와 메서드 사용하기

opne class Parent {
    var hello: String = "안녕하세요."
    fun sayHello() {
        Log.d("inheritance", "$hello")
    }
}
class Child : Parent() {
    func myHello() {
        hello = "Hello"
        sayHello()
    }
}

오버라이드

부모 클래스의 프로퍼티나 메서드를 자식 클래스에서 재정의하여 사용하려고 할 경우 부모 클래스의 프로퍼티와 메서드는 open 키워드로 열려 있어야만 오버라이드 할 수 있습니다.

익스텐션

코틀린은 클래스, 메서드, 프로퍼티에 대해 익스텐션(확장)을 지원하며 이미 만들어져 있는 클래스에 메서드를 추가하는 메서드 익스텐션을 주로 사용합니다.

fun 클래스.확장할 함수() {
    // ...
}

확장을 한다고 해서 실제 클래스의 코드가 변경되는 것은 아니며 단지 실행 시에 . 연산자로 호출해서 사용할 수 있도록 해줍니다.

설계 도구

패키지

클래스와 소스 파일을 관리하기 위한 directory 구조의 저장 공간입니다.

package main_directory. sub_directory
class 클래스 {

}

추상화

명확한 코드는 설계 단계에서 코드를 작성하는데, 그렇지 않은 경우에는 구현 단계에서 코드를 작성하도록 메서드의 이름만 작성하는 것을 추상화(abstract)라고 합니다. 추상화된 클래스나 메서드는 abstract 키워드를 사용하여 명시해야 하며 구현 단계에서 이 추상화된 클래스를 상속 받아 내부 코드를 구현합니다.

abstract class Design {
    abstract fun drawText()
}

class Implements : Design() {
    fun drawText() {
        // 구현
    }
}

인터페이스

추상화랑 비슷하지만 실행 코드가 있을 수 있는 추상화와 달리 인터페이스는 메서드 이름만 나열한 것입니다. 인터페이스는 상속 관계의 설계보다는 외부 모듈에서 내가 만든 모듈을 사용할 수 있도록 메서드의 이름을 나열해둔 일종의 명세서로 제공됩니다.

인터페이스는 interface 예약어를 사용하여 정의하며 추상화와는 다르게 class 키워드를 사용하지 않습니다. 코틀린에서는 프로퍼티도 인터페이스 내부에 정의할 수 있습니다.

interface 인터페이스명 {
    var 변수: 타입
    fun 함수1()
    fun 함수2()
}

인터페이스를 실제로 구현할 때는 상속과는 다르게 생성자를 호출하지 않고 인터페이스 이름만 지정해주면 되며 구현하는 프로퍼티나 메서드는 override 키워드를 사용해야 합니다.

class 클래스명 : 인터페이스명 {
    override var 변수명: 타입 =override fun get() {
        // 구현
    }
}

코틀린에서 인터페이스는 상속 형태가 아닌 소스 코드에서 직접 구현할 수도 있습니다. 이때 object 키워드를 사용하여 구현해야 합니다.

var 변수명 = object : 인터페이스명 {
    override var 변수명: 타입 =override fun get() {
        // 구현
    }
}

접근 제한자

코틀린에서 클래스, 인터페이스, 함수, 변수는 모두 접근 제한자를 가질 수 있습니다. 함수형 언어라는 특성 때문에 코틀린은 기존 객체지향에서 접근 제한자의 기준으로 삼았던 패키지 대신에 모듈 개념을 사용합니다.

함수형 언어, 함수형 프로그래밍
사이드 이펙트가 없는 순수 함수를 이용해 프로그래밍하는 기법. 사이드 이펙트란 함수가 결과값 이외에 다른 상태를 변경시키는 것을 말함

코틀린에서의 모듈
한 번에 같이 컴파일되는 모든 파일을 묶어 모듈이라고 함

접근 제한자를 사용하지 않을 경우엔 기본적으로 public 접근 제한자가 적용됩니다.

접근 제한자제한범위
private다른 파일에서 접근할 수 없음
internal같은 모듈에 있는 파일만 접근할 수 있음
protectedprivate과 비슷하나 상속 관계에서 자식 클래스가 접근할 수 있음
public제한 없이 모든 파일에서 접근할 수 있음

NULL

Nullable

코틀린에서 지정하는 기본 변수는 모두 null 값을 입력할 수 없습니다. null 값을 입력하기 위해서는 변수를 선언할 때 타입 뒤에 물음표(?)를 사용해야 합니다.

var 변수명: 타입?

함수 파라미터에 null 허용

함수 파라미터 역시 물음표를 사용하여 null 값을 허용할 수 있습니다. 이때 해당 파라미터에 대해 null 체크를 해야 그 파라미터를 사용할 수 있습니다.

fun nullParameter(str: String?) {
    if (str != null) {
        var length = str.length
    }
}

함수의 리턴 타입에 null 허용

함수의 리턴 타입에도 물음표를 붙여 null 값을 허용할 수 있습니다.

fun nullReturn(): String? {
    return null
}

안전한 호출

물음표와 온점(?.)을 사용하면 null 체크를 좀 더 간결하게 할 수 있습니다. 이를 Safe Call이라고 합니다. 만약 변수가 null일 때 ?. 다음의 메서드나 프로퍼티는 호출되지 않습니다.

fun testSafe(str: String?): Int? {
    var resultNull: Int? = str?.length
    return resultNull;
}

NULL 값 대체하기

물음표와 콜론(?:)을 사용하면 변수가 null일 때 넘겨줄 기본값을 설정할 수 있습니다. 이를 Elvis Operator라고 합니다.

fun testElvis(str: String?): Int {
    var resultNonNul: Int = str?.length?:0
    return resultNonNull;
}
profile
안드로이드 개발자를 꿈꾸는 사람

0개의 댓글