# 1. Language/🔰 Kotlin

Kotlin # 변수/Null/연산자/형변환

둥굴둥굴둥굴레차 2022. 6. 29. 16:34

🎈 변수

변수를 만들 때 자료형을 명시하지 않는 경우가 있기 때문에 var나 val을 사용하여 변수라는 것을 표시해주어야 한다.

만약 자료형을 명시하지 않는 경우엔 그 문자열에 맞는 변수상자가 내부적으로 만들어진다. 일명 '자료형 추론'이라고 한다.

예)

var changeYes
val CHANGE_YES

 

자료형을 명시하지 않고 변수를 선언하는 것은 괜찮지만, 초기값을 설정하지 않는 경우는 에러가 난다!

 

예)

// 가능
var name:String = ""
var name = ""
var name:String

// 불가능
var name

 

만약 처음에 넣어둘 값을 잘 모르겠다면, lateinit키워드를 추가하면 된다.

 

lateinit

  • var 속성에만 사용 가능
  • null허용 자료형에 사용불가
  • 기본 자료형에 해당하는 속성에 사용불가
    • int, boolean, float, double 등
  • 생성자에 사용불가
  • 사용자 정의 Getter/Setter 속성에 사용불가

예)

class User {
    lateinit var age: Int
    lateinit var name: String

    constructor(age: Int, name: String) {
        this.age = age
        this.name = name
    }
}

 

 

🎈 변수의 종류

var

변수상자에 값을 넣거나 빼는 것이 모두 가능

코딩컨벤션 : var을 선언할 때는 소문자로 선언 및 카멜케이스를 적용한다.

val

변수 상자에 한 번 값을 넣으면 빼는 것만 가능. 즉, 값을 바꿀 수 없는 읽기 전용 변수
값을 쉽게 바꿀 수 없다보니 상수와 비슷함. 하지만 언제 어디서든 접근가능한 것은 아님.
(실제 앱을 만들다보면 val을 사용하는 경우가 더 많다.)

코딩컨벤션 : val을 선언할 때는 대문자로 선언 및 스네이크 스타일을 적용한다.


 

🎈 읽기전용이며 언제 어디서든지 접근이 가능한, 상수를 만드는 방법

  1. companion object 사용
  2. 패키지 변수 사용

예) companion object사용

  • const val 키워드를 사용하면 상수를 선언할 수 있음.
  • BONUS라는 이름의 상수를 생성.
  • companion object키워드로 만든 객체는 동반 객체라고도 부름.
  • 동반객체 안에 정의한 변수나 함수는 클래스의 이름으로 직접 접근할 수 있음.
    (ex. MainActivity.BONUS)
class MainActivity : AppCompatActivity() {
    var first:Int = 0
    var second:Int = 0

    companion object {
        const val BONUS = 100
    }

    override fun onCreate(savedInstanceState: Bundle?) {

예) 패키지 변수 사용
* constants란 이름의 패키지를 생성
* 해당 폴더에 새 Kotlin class파일을 생성
* 해당 파일에 아무런 클래스 없이 아래와 같은 코드를 집어넣으면, 해당 변수는 패키지 이름과 변수 이름만으로 접근할 수 있는 상수가 됨.

 

constants 파일의 소스코드

package org.techtown.basic4.constants

var bonus:Int = 100

MainActibity.kt 파일의 소스코드

중략...
import org.techtown.basic4.constants.bonus

class MainActivity : AppCompatActivity() {
중략...
    override fun onCreate(savedInstanceState: Bundle?) {
        addButton.setOnClickListener {
중략...
    val result = first + second + bonus
    outputTextView.append("더하기의 결과는 : ${result}")
    }
  }
}

 

 


 

🎈 자료형

Kotlin은 '타입 기반의 언어'기 때문에 변수를 만들 때 아래와 같이 자료형을 함께 명시해준다.

var count:Int = 0

 

🎈 Null허용 자료형

우선, Null이란 다음과 같다.

Java에서는 변수값이 null인지 확인하는 과정을 거치며 이 때 null이면 프로그램에 오류가 발생하도록 되어있다.

Kotlin에서는 이러한 문제를 줄이기 위해 변수에 null을 직접 할당하지 못하게 하고 null허용 자료형으로된 변수를 따로 만들어 null을 할당할 수 있도록 한다. 이렇게 되면 값이 null인 경우에도 에러를 발생시키지 않도록 만들 수 있다.

 

예) 자료형에 null을 허용시킨 것은 래핑(Wrapping)이라 한다.

var name:String?

예) 이를 다시 되돌리는 과정을 언래핑(Unwrapping)이라 한다.

name!!

 

실습코드

val NUMBER1: Int? = null
//val NUMBER2: Int = null -> 에러발생.

var number1: Int? = 2+5
var number2: Int? = 10
//var number3: Int? = number1 + number2 -> 에러발생. number1과 number2는 null이 될 수도 있다고 설정되어있기 때문.

var number3: Int? = number1!! + number2!! // -> 에러발생X.
// ?를 통해 null혹은 숫자가 될 수 있다고 내가 설정해뒀긴한데, 나 믿고 숫자라고 생각해 라는 의미의 !!를 추가해주었기 때문.

println(number3)
// 다만 주의할 점은, 사실 null일 경우엔 NullPointerException이 발생할 수 있다.

// 결론!!
// 100% 확신하는 경우가 아니면 !!는 사용하지 말자.

 

🎈 Null Safety

 

//?
val number: Int = 10 // non-nullable Int
val number: Int? = null // nullable Int

//!! -> 정말 필요한 경우에만 사용하기
val nullableNumberList: List<Int?> = listOf<Int?>(1, 2, 3, 4, 5)
var result: Int = 0

nullableNumberList.forEach {
    result += it!!
}

// ?.
val text: String? = "txt"
//val text: String? = null
println(text?.length)

// !!.
//println(text!!.length) -> NullPointerException이 발생해야함

// as?
open class Warrior(var name: String, var power: Int, var type: String){
    fun attack(){
    println("공격")}
}

class DefenceWarrior (var name: String, var power: Int){ // 상속안함
    fun defence(){
        println("방어")
    }
}

val defenceWarrior = DefenceWarrior("가", 123)
val warrior = defenceWarrior as? Warrior
//val warrior = defenceWarrior as Warrior -> 에러 발생

//println(warrior)

// ?: 엘비스 연산
val text2 : String? = "123"
val nullText: String? = null

var len1: Int = if(text2 != null) text2.length else 0
var len2: Int = text2?.length ?: 0

🎈 Any자료형

어떠한 값이라도 넣을 수 있는 자료형. 충분한 메모리 공간을 가지고 있음.

 

is 연산자

Any자료형에 어떤 자료형인지 확인할 수 있는 연산자.

 

예)

val input1:Any = "10"
if (input1 is String) {
    val output:String = input1 as String
    outputTextView.append("input1은 문자열")
}

 

as?

위의 예시에서, input1의 값이 숫자로 변환될 수 있는 "10"이 아닌 "가"와 같은 값이라면 예외가 발생할 것임.
예외상황을 만들지 않으려면 변환이 불가능할 경우 null을 반환해줄 수 있도록 as?를 사용하자.

 

예)

val input1:Any = "10"
if (input1 is String) {
    val output:String = input1 as? String
    outputTextView.append("input1은 문자열")
}

 

형변환

 

문자열 -> 숫자

class MainActivity : AppCompatActivity() {
    var first:Int = 0
    var second:Int = 0

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        addButton.setOnClickListener {
            val firstStr = firstInput.text.toString()
            val secondStr = secondInput.text.toString()

            first = firstStr.toInt()
            second = secondStr.toInt()

            val result = first + second
            outputTextView.setText("더하기 결과 : ${result}")

 

상속한 클래스 간의 캐스팅

open class Warrior(var name: String, var age: Int) {
    open fun attack(){ // 오버라이드 해주기 위해 open시키자
        println("공격")
    }

}

class DefenceWarrior(name: String, age: Int, height: Int): Warrior(name, age){

    fun defence() {
        println("방어")
    }
}

val warrior: Warrior = DefenceWarrior("박소현", 29, 349) // var는 변경이될 수 있기 때문에 스마트 캐스팅이 안된다.
println(warrior.attack()) // warrior.defence()는 사용 불가능. defence기능을 포기하고 warrior타입이 되었기 때문에.

// is -> 타입 체크. true or false가 리턴된다. 그리고 스마트캐스팅 해줌.
if(warrior is DefenceWarrior){
    // 스마트 캐스팅
    // -> 내가 만든 warrior를 if블럭 안에서는 defenceWarrior로 사용하게 해준다
    warrior.defence()
}

// as -> 지정한 타입으로 캐스팅을 시도하고 불가능한 경우에는 예외발생
val warrior2: DefenceWarrior = warrior as DefenceWarrior
warrior2.defence()