프로그래밍/안드로이드+코틀린
-
코틀린 기본 Basic of Kotlin2020.12.21
코틀린 기본 Basic of Kotlin
*변수 선언
방법 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) ?:는 세계적으로 유명한 엘비스 프레슬리로부터 유래되었습니다. 사람들이 :)를 웃는 표시로 많이 사용하는 것처럼 ?:도 엘비스 프레슬리의 머리 모양을 따서 사용합니다.
'프로그래밍 > 안드로이드+코틀린' 카테고리의 다른 글
안드로이드 스튜디오 뒤로가기(back) 버튼 감지하는 법 (0) | 2020.12.27 |
---|---|
안드로이드 액티비티 생명 주기 (0) | 2020.12.21 |
안드로이드 스튜디오 로그 log 정리 (0) | 2020.12.19 |
안드로이드 플랫폼 구조(Platform Architecture) (0) | 2020.12.19 |
해결방법 :prepareKotlinBuildScriptModel Task fails in a Java project (0) | 2020.11.25 |