코틀린 기본 Basic of Kotlin

2020. 12. 21. 00:34
반응형

*변수 선언

 방법 1.

   var 변수명 = 값

   ex. var myName = "홍길동"

 

 방법 2.

   var 변수명: 타입

   변수명 = 값

   ex. var myAge: Int

        myAge = 27

        myAge = "홍길동" // 타입이 Int인 곳에 String 데이터 타입을 넣고 있으므로 오류가 납니다.

 

*데이터 타입

데이터 타입은 기본적으로 다른 언어들과 많이 비슷합니다.

 - 굳이 선정해본 특징

 1. 모든 데이터 타입의 첫글자는 대문자로 시작합니다.

 2. String은 Primitive type은 아닙니다. 다만 사용빈도가 높습니다.

 3. Char과 String의 차이는 Char는 한 개의 문자이고, String은 여러 개의 문자, 즉 글입니다.

 4. Double과 Float 형을 구분하기 위해 Float 변수의 값 뒤에 F를 붙입니다. (ex. 3.141592F) 이는 var temp = 3.141592로 선언했을 때 default로 double data type으로 생성된다는 것과 같은 의미입니다.

 5. Long 또한 마찬가지로 Int와 구분하기 위해 변수의 값 뒤에 L을 붙입니다. (ex. 12345L)

 

예시

$가 붙는 것은 String이 아닌 변수임을 알려줍니다.

 

*Kotlin 변수 특징

1. val은 변수의 값을 변경하지 못합니다. 그래서 val PI = 3.141592와 같은 값을 선언하기 좋습니다.

2. var bigger = if (a > b) a else b

   이렇게 변수에 직접 if문을 사용할 수 있습니다.

3. var bigger = if (a > b) {

   a = a - b

   a }

   이렇게 마지막 줄에 선언된 값이 bigger에 저장됩니다. (scala와 비슷합니다.)

4. 문자열 안에서 수식을 사용할 수 있습니다. 

  "문자열 $변수 문자열", "문자열 ${변수 + 1} 문자열", "문자열 ${변수} 문자열"과 같은 방법을 사용할 수 있습니다.

 

 

Kotlin에서 제어문은 if, when, 반복문은 for, while이 있습니다.

*조건문 when(switch문이 없고 더 upgrade된 when이 있습니다.)

 - 형식

 when(파라미터) {

   비교값1 -> {

  }

   비교값2 -> {

 

  }

   else -> {

 

  }

}

 - 비교값에서는 콤마로 구분해서 한 번에 비교할 수도 있습니다.

 - 비교값에 in을 사용해서 범위로 값을 비교할 수도 있습니다.

 

 

 

*배열(Array)

var students = IntArray(10)

var DoubleArray = DoubleArray(10)

var StringArray = Array(10, {item->""}) //String은 Primitive type이 아니기 때문에 위와 같이 
                                         //선언해야 합니다.

var dayArray = arrayOf("Mon", "Tue", "Wed") //이렇게 직접 String값을 할당할 수도 있습니다.

 

배열명[인덱스] = 값

배열명.set(인덱스, 값) //위 문장처럼 값을 할당하는 것과 아래 문장처럼 값을 할당하는 것은 같은 syntax입니다.

 

배열의 범위를 벗어나서 값을 할당하면 java.lang.ArrayIndexOutOfBoundsException: 에러가 발생합니다.

 

배열명[인덱스], 배열명.get(인덱스)로 배열의 값에 접근할 수 있습니다.

 

 

*컬렉션(Collection)

 컬렉션은 배열과 달리 동적으로 사이즈를 할당할 수 있어서 동적 배열이라고도 부릅니다.

 컬렉션은 크게 세 가지로 리스트(List), 맵(Map), 셋(Set)이 있습니다.

 그냥 List, Map, Set으로 사용하는 것이 아닌 mutableList, mutableMap, mutableSet으로 사용하는 것이 일반적입니다. 참고로 Mutable은 사전적 의미로 "변할 수 있는"이라는 뜻입니다. 그냥 List, Map, Set은 Immutable로 한 번 입력된 값은 val처럼 변할 수 없지만, 앞에 prefix로 mutableList와 같이 사용한다면 입력된 값을 수정할 수 있습니다. val처럼 그냥 mutableList는 예를 들어 val DAY_LIST = listOf("월", "화", "수") 이런식으로 사용하고는 합니다. Kotlin에서는 변하지 않는 값에는 모두 대문자로 변수명을 설정해줍니다. C언어에서도 #define PI 3.141592라고 선언했던 것과 비슷합니다.

 

- List 

 var stringList = mutableListOf<String>() // 이렇게 빈 리스트를 선언할 수 있다. 

                                           // var 변수명 = mutableListOf<각 값들의 타입>()

                                           // <> 이 괄호는 Generic입니다. 코틀린에서 컬렉션은 
                                           // Generic을 사용하지 않으면 생성할 수 없습니다.

 var mutableList = mutableListOf("MON", "TUE", "WED")

 mutableList.add("THU") // 리스트에 값 추가

 mutableList.get(1) // 리스트에 입력된 값 사용

 mutableList.set(1, "수정할 값") // 리스트 값 수정하기

 mutableList.removeAt(1) // 리스트에 입력된 값 제거하기, TUE를 제거합니다. 
                         //그러면 WED가 앞으로 한칸 당겨져서 1번자리에 WED가 오게 됩니다.

 Log.d("Collection", "${mutableList.size}개의 데이터가 있습니다.") // size는 property입니다. 
                                  //괄호가 있으면 함수, 괄호가 없으면 property라고 칭합니다.

 

 - Set

Set은 중복을 허용하지 않는 List입니다. 리스트와 유사하지만, 인덱스로 조회할 수도 없고, get함수도 지원하지 않습니다. List보다 난 것은 데이터를 삭제할 때 좀 더 편합니다. dataSet.remove("FEB")처럼 특정 값을 직접 조회해서 삭제할 수 있습니다.

 

- Map

Map은 Key와 Value의 쌍으로 입력되는 Collection입니다. Map의 Key는 List에서의 Index와 비슷하나 List와는 달리 Key를 직접 입력해야 합니다.

 var map = mutableMapOf<String, String>() // key와 Value를 모두 String으로 설정한 map입니다. 
                                    //첫 번째 String이 key이고, 두 번째 String이 value입니다.

 map.put("키1", "값1")

 map.put("키2", "값2")

 map.put("키3", "값3")

 Log.d("CollectionMap", "map에 입력된 키1의 값은 ${map.get("키1")}입니다.") //get()함수에서 키를
                                                        // 직접 입력해 값을 꺼낼 수 있습니다.

 map.put("키2", "수정") // 새로운 값을 해당 키에 입력하면 Map의 Value를 수정할 수 있습니다.

 map.remove("키2") // List에서 removeAt을 통해 인덱스의 값을 삭제하면 하나씩 당겨졌는데, 
                   //Map에서는 Key와 Value가 모두 사라집니다. 어쩌면 당연한 것 같기도 합니다.

 

 

cf) Collection 값의 단위는 Element입니다. 그냥 Value라고 해도 되지만 Map의 경우 각 Key마다 Value가 따로 있기 때문에, (Key, Value)를 묶은 한 개체(단위)를 Element라고 부릅니다.

 

 

 

*반복문

- for

//in을 사용해서 반복하는 범위를 저장할 수 있습니다.

for(index in 1..10){

   //내용 입력

}



//array.size가 끝날 때까지라는 조건을 until로 줍니다.

var array = arrayOf("JAN", "FEB", "MAR", "APR")

for(index in 0 until array.size) {

   //내용 입력

}



//C, JAVA의 for문에서 맨 마지막에 i를 얼마나 증가시킬 것에 대한 조건을 Kotlin에서는 step 뒤에 적어주면서 처리할 수 있습니다.

for(index in 0..100 step 3){

   //내용 입력

}



//값을 감소시키면서 처리할 수 있습니다.

for(index in 10 downTo 0 step 3){ // 10부터 0까지 3씩 건너뛰면서 값을 감소시킵니다. 출력 결과는 10 7 4 1

   //내용 입력

}



//반복의 조건에 숫자 값이 아닌 Array나 Collection이 올 수도 있습니다.

var array = arrayOf("JAN", "FEB", "MAR", "APR")

for(month in array){
   //내용 입력

}

 

-while문은 다른 언어의 while문과 유사하며 do-while문 또한 지원한다.

 

 

*함수

fun 함수명(parameter 이름: 타입): return 타입 {//parameter와 return 값은 없을 수도 있는데, 그러면 적지 않아도 됩니다.

   return 값

}

 

fun tempFunc((val 생략) name1 : String, name2 : Int = 123, name3 : Double) { 실행코드 }

 - 함수 parameter는 변하지 않는 immutable, 즉 val이 생략된 형태입니다.

 - name2 : Int = 123과 같이 default값을 설정해줄 수 있습니다.

 - 함수를 호출할 때, tempFunc("John", name3 = 1.23) 이렇게 parameter 이름으로 값을 입력해서 보낼 수 있습니다.

 - C언어 같은 경우 함수를 호출하기 전에 함수가 먼저 선언되어 있어야 하는데, Kotlin에서는 그럴 필요 없이 함수가 호출되는 시점 뒤에서 선언되어 있어도 호출할 수 있습니다.

 

 

*클래스(Class)

Class란? 그룹화할 수 있는 함수와 변수를 한군데 모아놓고 사용하기 쉽게 이름을 붙여놓은 것을 Class(클래스)라고 이해하면 됩니다. Class 내부에 정의되는 변수와 함수를 멤버 변수, 멤버 함수라고 부릅니다. 또 다른 용어로는 Property(프로퍼티), Method(메서드)라고 부르기도 합니다. Class 내에 정의된 변수는 Property라고 하는데, Class 내의 함수 안에 정의되어 있는 것은 Property라고 하지 않고 그냥 변수(혹은 지역변수)라고 합니다.

 

var apple = Apple() // Apple class의 생성자를 호출해 apple 변수에 담는 것인데, 이 때 apple은 instance라고 한다.
var pear = Pear(10) // 초기화 시 parameter가 필요하면 parameter를 괄호 안에 적어주면 됩니다.

 

-Primary constructor(프라이머리 생성자)

class AppleOne constructor(value: String) { // constructor keyword를 통해 생성자임을 명시합니다.
   // 코드
}

class AppleTwo (value: String) { // constructor keyword를 생략할 수도 있습니다.
   // 코드
}

class AppleThree {
   init { // Class 생성자가 호출되면 init 블록의 코드가 실행됩니다.
      Log.d("class", "${value}입니다.")
   }
}

class AppleFour { // 아래의 Constructor는 Primary 생성자가 아닌 Secondary 생성자입니다.
   constructor (value: String){ // constructor를 함수처럼 사용할 수도 있습니다.
      Log.d("class", "${value}입니다.")
   }
}

 

-Class를 instance화 하지 않고 사용하는 법 = Companion Object

class AppleFive{
   companion object {
      fun printHello(){
         Log.d("Companion", "Hello world!")
      }
   }
}

AppleFive.printHello() // 이와 같이 생성자 없이 바로 Class에서 함수를 호출하여 사용할 수 있습니다.

Log.d(), Log.e()가 모두 companion object입니다.

 

-Data Class(데이터 클래스)

Data Class는 간단한 값의 저장 용도로 사용됩니다. class 앞에 data예약어를 붙여서 만들 수 있습니다. 일반적인 Class와는 다르게 Class 명 다음에 Parameter를 정의할 수 있는데, 이 Parameter 앞에는 var과 val을 꼭 붙여줘야 합니다.

data class DataUser (var name: String, var age: Int)
var dataUser = DataUser("Michael", 21)
Log.d("DataClass", "DataUser는 ${dataUser.toString()}")
var newUser = dataUser.copy() // 이와 같이 copy() method를 지원합니다.

 

-Class Inheritance(클래스 상속)

 1. 부모 클래스를 open keyword로 만들어야만 자식 클래스에서 사용할 수 있습니다. open keyword가 없다면 상속받을 수 없습니다.

 2. 부모 클래스에 세컨더리 생성자가 있다면, 자식 클래스의 센컨더리 생성자에서 super 키워드로 부모 클래스에 전달할 수 있습니다.

 3. Override(오버라이드, Property와 Method의 재정의)

   -> 상속할 때 method 앞에 open 키워드를 붙이면 오버라이드 할 수 있습니다. 만약 open키워드가 없다면 method를 override할 수 없습니다.

   -> Property(변수) 또한 마찬가지로 open으로 열려 있어야만 override할 수 있습니다.

open class BaseClass2 { // Open Class
   open var opened: String = "I am" // Open Property
}

class ChildClass2 : BaseClass2() {
   override var opened: String = "You are" // Override Property
}

 4. Extension(익스텐션)을 지원합니다.

   -> 미리 만들어져 있는 Class에 Method를 붙여넣는 개념입니다. Method를 확장합니다.

fun String.plus(word: String): String { // 기존 String Class에 plus라는 extension을 추가합니다.
   return this + word // 기존 값에 word를 추가해서 반환합니다.
}

 

 

*추상화(Abstract)

부모 클래스에서 직접 Method에 대한 설명을 하지 않고 자식 클래스에서 Method의 자세한 내용을 적어주는 것입니다.

abstact class Animal {
   fun walk() {
      // 코드
   }
   abstract fun move() // 추상화 함수를 abstract로 표현합니다.
}

class Bird : Animal() {
   override fun move() {
      // move에 대한 자세한 코드를 명시합니다.
   }
}

 

*인터페이스(Interface)

 어떤 클래스에 실행코드가 한 줄이라도 있으면 추상화, 실행 코드 없이 Method 이름만 나열되어 있으면 인터페이스입니다. 실제 구현하는 부분에서 override를 써줘야하는 것을 잊지 말아야 합니다.

interface InterfaceKotlin {
   // Property와 Method 앞에 abstract 문구가 생략되어 있습니다.
   var variable: String 
   fun get() // 실행 코드 없이 이름만 작성해놓습니다.
   fun set()
}

class RealKotlin : InterfaceKotlin { // 실질적인 실행코드가 입력되는 부분입니다.
   override var variable: STring = "init"
   override fun get { //코드 }
   override fun set { //코드 }
}

// 꼭 클래스에서만 사용하는 것이 아닌 아래처럼 소스코드에서 직접 구현하는 형태입니다.
// object 키워드를 사용하여 구현할 수 있습니다.
var realKotlin = object : InterfaceKotlin {
   override var variable: String = "init"
   override fun get { //코드 }
   override fun set { //코드 }
}

 

 

*접근 제한자

private : 다른 파일에서 접근할 수 없습니다. 자식 클래스에서도 접근이 불가능합니다.

internal : 같은 모듈에 있는 파일만 접근할 수 있습니다.

protected : private과 같으나 상속 관계에서 자식 클래스가 접근할 수 있습니다.

public : 제한 없이 모든 파일에서 접근할 수 있습니다.

cf) 코틀린에서 모듈(Module)이란 한 번에 같이 컴파일되는 모든 파일을 말합니다. 안드로이드에서는 하나의 앱이 하나의 모듈이 될 수 있고, 라이브러리도 하나의 모듈이 될 수 있습니다.

 

 

*Generic(제네릭)

제네릭은 입력되는 값의 타입을 자유롭게 사용하기 위한 설계 도구입니다. 

public interface MutableList<E> {
   var list: Array<E> // 자주 사용되는 MutableList입니다.
   ...
}

 var list: MutableList<String> = mutableListOf("JAN", "FEB", "MAR")

 

 

*Null Safety

- ? (Nullable)

코틀린이 다른 언어보다 뛰어난 부분 중 하나인 파트입니다. 코틀린에서 지정하는 기본 변수는 모두 null이 입력되지 않습니다. null을 입력하기 위해서는 변수를 선언할 때 타입 뒤에 ?(Nullable, 물음표)를 입력하면 됩니다.

var variable: String? // 물음표는 variable에 Null이 들어올 수 있음을 의미합니다.
variable = null

var variable2 : String
variable2 = null // null을 입력할 수 없습니다. 오류입니다.

함수 Parameter에서도 ?를 통해 null을 입력받을 수 있습니다. 단 사용하기 전 null인지 확인하고 사용해야 합니다.

함수의 return type에서도 null을 사용할 수 있습니다.

fun nullParameter(str: String?) { // Parameter로 null을 받을 수 있습니다.
   if(str != null) { // str이 null인지 확인하고 조건문 안에서 사용합니다.
      // 코드
   }
}   

fun nullReturn(): String? {
   return null
}

 

- ?. (Safe call, 안전한 호출)

Nullable 변수인 ? 다음에 .을 사용하면 변수가 null인 경우 ?. 다음의 Method나 Property를 호출하지 않습니다.

fun testSafeCall(str: String): Int? {
   var resutlNull: Int? = str?.length // 만약 str이 null값으로 넘겨졌다면 length는 실행하지않고
                                      // resultNull에 null을 넣고 반환합니다.
   return resultNull
}

 

 

- ?: (Elvies operator, Null 값 대체하기)

null인 변수가 있다면 null을 반환하지 않고 ?: 뒤에 나오는 값으로 반환합니다.

fun temp(str: String?): Int {
   var resultNonNull: Int = str?.length?:0 // 만약 str이 null이어서 str?.length가 null이라면
                                           // null을 반환하는 것이 아닌 0을 반환합니다.
   return resultNonNull
}

cf) ?:는 세계적으로 유명한 엘비스 프레슬리로부터 유래되었습니다. 사람들이 :)를 웃는 표시로 많이 사용하는 것처럼 ?:도 엘비스 프레슬리의 머리 모양을 따서 사용합니다.

반응형

+ Recent posts