[Kotlin] 코틀린 문법 정리 - 작성중

조윤환·2023년 6월 1일

Kotlin-image

1. 기본 문법


1-1. 변수와 자료형

Kotlin에서는 Int, Double, Float, Char 등 자료형을 먼저 선언할 필요가 없다.
모든 기본 자료형을 객체로 만들어서 관리하기 때문이다.

변수 선언 시 val, var 두 가지 키워드만 사용한다.

  • var: 선언 이후 값을 다시 저장할 수 없다.
  • val: 선언 이후 값을 다시 저장할 수 있다. (read only!!)
var age: Int = 27
val name: String = '조윤환'

// 자료형 생략 시 저장하는 값에 따라 자료형이 자동으로 결정된다.
val birth = '1997.09.03'

null 허용 변수

변수를 선언할 때, null 값의 허용여부를 결정할 수 있다.
다음과 같이 자료형 뒤 '?' 키워드를 통해 허용 여부를 설정한다.

val hobby: String? = null

// 에러
// ? 키워드가 없기 때문에 아래 변수는 null 값을 가질 수 없다.
val hobby2: String = null

Java를 이용해 프로그래밍을 하면 NullPointException이라는 에러를 자주 접하게 된다. 해당 에러는 프로그램 실행 과정에서 빈공간에 접근했을 때 주로 발생한다.

Kotlin의 장점

Kotlin은 null 허용 변수를 통해 실행 시점에 오류를 발생시키는 대신 컴파일 시점 검사를 통해 오류를 방지한다.

1-2. 함수

// 매개변수의 타입 설정이 필요하다.
// 매개변수의 기본 값을 설정할 수 있다.
// 리턴타입을 생략할 경우, 컴파일 과정에서 자동으로 Unit 키워드가 추가된다.
fun testFunction(value: Int, value2: Double = 0.0): Int{
	// code
}

함수 오버로딩

똑같은 이름의 함수를 사용하고 싶을 때, 매개변수의 갯수, 매개변수의 타입을 달리한다.

fun add(a: Int, b: Int): Int {
	return a + b
}

fun add(a: Double, b: Double): Double {
	return a + b
}

fun add(a: Int, b: Int, c: Int): Int {
	return a + b + c
}

주의할 점은 리턴타입은 함수 오버로딩에 결정요소가 아니다.

1-3. 제어문

IF

if (조건식) { 
	// code
} else if (조건식){
	// code
} else {
	// code
}

// 조건 할당
val a = if (조건식) 10 else 20

WHEN

val a = 2
when (a){
	1 -> print("a는 1")
    2 -> print("a는 2")
    3, 4 -> print("a는 3 또는 4")
    in 5..10 -> print("a는 5 ~ 10 사이의 숫자")
    else -> print("a는 1 ~ 10사이의 숫자가 아님")
}

FOR, WHILE

val a = 1..10
for(item in a){
	// code 
} 

val a2 = 1
while(a < 10){
	a2 += 1
}
// IntRange 자료형
val a1 = 1..10
// 1, 3, 5, 7, 9
val a2 = 1..10 step 2
// 10, 9, 8, 7 .. 1
val a3 = 10 downTo 1
// 10, 8, 6, 4, 2
val a4 = 10 downTo 1 step 2

2. 객체


객체란 현실의 대상을 컴퓨터에 표현하기 위한 수단이다.
그렇기 때문에 객체는 대상의 상태(형태, 외모, 정보 등)를 나타내는 변수와 대상의 행동을 나타내는 메서드를 갖는다.

Java의 객체지향과 차이

Java의 경우 모든 코드를 클래스 내부에서 작성해야 하기 때문에, 현실의 대상을 표현하기 위한 수단이 아니더라도 클래스와 객체를 생성해야 한다.
하지만 Kotlin은 일반 함수도 지원하기 때문에, 객체를 본래 목적에 맞게 생성 및 사용할 수 있다.

class Student{
	// 멤버 변수
    var studentId: Int = 0
    var name: String = ""
    
    // 메서드
    fun testMethod(){
    	// code
    }
}

2-1. 생성자

생성자란 클래스를 통해 객체를 생성할 때, 자동으로 수행될 코드를 작성하는 곳이다.
주로 멤버 변수의 초기화를 위해 사용한다.

class Student{
	var studentId: Int = 0
    var name: String = ""
    
    constructor(){
    	// 매개변수가 없는 생성자
    }
   
   	// 매개변수의 개수나 자료형을 달리하여 여러개의 생성자를 만들 수 있다.
    constructor(id: Int, name: String){
    	// 매개변수가 있는 생성자
    }
}

기본 생성자

기본 생성자는 클래스를 정의할 때 클래스 이름 우측에 정의하는 생성자다.
기본 생성자의 매개 변수는 자동으로 멤버 변수로 등록된다.

// constructor 키워드는 생략가능하다.
// val/var 키워드가 없을땐, 멤버 변수로 자동 등록되지 않는다.
class Student constructor(var studentId: Int, var name:String){
	/* 생략 가능 코드
    var studentId: Int = 0
    var name: String = ""
    
    constructor(id: Int, name:String){
    	this.studentId = id
        this.name = name
    }
    */
}

기본 생성자를 제외한 나머지 생성자를 보조 생성자라고 부른다.
만약 기본 생성자가 정의되어 있다면, 보조 생성자는 반드시 기본 생성자를 호출해야 한다.

class Student(var studentId: Int, var name: String){
	constructor(id: Int): this(id, "younhwan"){
    	// 보조 생성자
    }
}

// 실행 흐름
// 보조 생성자 진입 -> 기본 생성자 호출 -> 보조 생성자 내부 코드 실행

// init 코드 블럭이 있다면?
// 보조 생성자 진입 -> 기본 생성자 호출 -> init 블럭 실행 -> 보조 생성자 내부 코드 실행

2-2. 상속

클래스를 설계할 때 다른 클래스가 가지고 있는 부분을 물려받는 것을 의미한다.
이를 통해 클래스 마다 중복된 부분을 하나의 클래스에 만들 수 있다.

// Java와 달리 Kotlin은 open 키워드가 없으면 final(상속 불가)로 선언된다.
open class Student(){}

class EngineeringStudent: Student(){}

class HumanitiesStudent: Student(){}

// 부모 클래스의 생성자는 반드시 호출해야 한다
// 부모 클래스의 생성자를 직접 호출하는 경우
class MedicalStudent: Student{
	constructor(): super{
    	// code
    }
} 

2-3. Property & 접근제한자

객체를 외부로부터 보호하기 위해 OOP에서는 캡슐화가 중요하다.

Kotlin 클래스의 멤버 변수와 메서드는 Java Bytecode로 변환될 때 자동으로 캡슐화된다.
즉, 멤버 변수는 private 제한자가 설정되고, 멤버 변수를 조회 및 수정하기 위한 getter, setter 메서드가 자동 생성된다.

decompile

이때 Kotlin의 접근제한자는 이러한 getter, setter의 생성여부를 결정한다.

  • private: 외부에서 멤버 변수에 접근할 수 없다.
    → getter, setter가 생성되지 않는다.
  • public: 외부에서 멤버 변수에 접근할 수 있다. (기본)
    → getter, setter가 생성된다.
  • protected: 상속관계일 경우에만 접근할 수 있다.
    → Java의 protected 제한자가 설정된 getter, setter가 생성된다.

val로 선언된 변수는 read only다.
그렇기 때문에 setter 메서드가 생성되지 않는다.

만약 멤버 변수에 대한 getter, setter 메서드를 직접 생성하고 싶을 때는 아래와 같이 사용한다.

class Student{
	var studentId: Int = 0
    	get(){
        	print("studentId is ${field}")
            return field
        }
        set(value){
        	print("set studentID $value")
            field = value
        }
}

custom-setter-getter

2-4. 지연초기화

변수를 선언할 때 반드시 적당한 값으로 변수를 초기화해야 한다.

하지만 사용자의 입력을 통해 값을 설정하거나 프로그램 실행 중에 값을 설정하고 싶은 경우가 있을 수 있다. 보통 이러한 경우 의미없는 값을 초기화하곤 한다.

Kotlin에서는 의미없는 값으로 변수를 초기화하기 싫은 사용자를 위해 지연초기화 기능을 제공한다. 단, 변수를 사용하기 전에는 반드시 초기화 해야한다.

// init 블럭을 이용한 지연초기화 (var 변수만 가능)
class TestClass{
	// 자료형을 반드시 명시해야 한다.
	var a1: Int
    
    init{
    	a1 = 100
    }
}

// lateinit (var 변수만 가능)
class TestClass{
	// Int, Double, Float 등의 기본 타입은 lateinit을 지원하지 않는다.
    // 변수를 사용하기 전에는 반드시 초기화 해야한다.
	lateinit var a1: String
    
    fun setA1() {
    	if(::a1.isInitialized == false){
        	a1 = "test"
        }    
    }
}

// lazy
val a1: String by lazy {
	"test"
}
profile
Android & PS

0개의 댓글