안녕하세요? codingTrip입니다.
오늘은 "코틀린 프로그래밍 1/2(함수편)"
1단원 코틀린의 기본을 익혀요!
2장. 변수와 자료형, 연산자
2-3 검사와 자료형을 변환해보기
시작하겠습니다!
🧪 자료형 비교, 검사, 변환
▷ 코틀린의 자료형 변환
- 기본형을 사용하지 않고 참조형만 사용
- 서로 다른 자료형은 변환 과정을 거친 후 비교
코틀린은 기본형을 사용하지 않고, 참조형 자료형을 쓰고 있습니다.
서로 다른 자료형으로 변환하려면, 변환 메소드가 필요합니다.
그래서 바로 변환되지 않아요.
첫 번째 줄에서 a라는 변수를 선언했고, 이것을 Int형으로 정의하고, 1로 초기화했습니다.
두 번째 줄에서는 b라는 변수를 Double형으로 지정했습니다.
즉, a와 b는 자료형이 다릅니다.
만약, Double형인 b에 a를 할당하려고 한다면, 문제가 발생합니다.
세 번째 줄에서 c라는 변수 선언하고, Int형에 1.1 실수형태의 값으로 초기화한다면, 불일치로 오류가 발생합니다.
결국, 둘 다 자료형 불일치로 오류가 발생합니다.
- 변환 메서드의 이용
이렇게 오류가 발생하는 상황에서 우리가 할 수 있는 방법은 다음과 같습니다.
b라는 Double형의 변수를 선언하고 a.toDouble()로 변환 메서드를 사용합니다.
이렇게 하면 a가 b에 할당될 수 있습니다.
변환메서드의 종류는 많기 때문에 나중에 살펴보겠습니다.
- 표현식에서 자료형의 자동 변환
연산 수식을 사용할 때
위의 식에서는 자료형을 특정하지 않고 추론하게 했으므로
1뒤에 L을 붙여서 Long형입니다
Long형과 Int형의 연산은 일단 큰 자료형인 Long형으로 변환됩니다.
즉, 변수 result는 Long형이 됩니다.
▷ 변환 메서드의 종류
- toByte: Byte
- toLong: Long
- toShort: Short
- toFloat: Float
- toInt: Int
- toDouble: Double
- toChar: Char
👓 기본형과 참조형 자료형의 비교 원리
▷ 이중 등호(==)와 삼중 등호(===)의 사용
== 값만 비교하는 경우
=== 값과 참조 주소를 비교할 때
값만 비교하려면 ==을 사용하고,
참조 주소까지 비교하려면 ===을 사용해야 합니다.
(자바에서는 ==로 값과 참조 주소를 비교하므로 주의하세요!)
두 연산자가 다르기 때문에 꼭! 주의 하시기 바랍니다.
변수 a와 b를 값만 비교했을 경우에는 true로 나오고,
참조 주소까지 비교했을 경우에도 true로 나옵니다.
이 경우에는 128이라는 이 수치 값 자체가 해당 스택에 쌓여있기 때문에
참조 주소 자체가 128이기 때문에 주소도 같습니다.
▷ 참조 주소가 달라지는 경우
a, b는 128라는 같은 값을 갖고 있지만
변수 b는 null이 가능한 정수형으로 선언했으므로(Int?) 참조주소가 서로 달라집니다.
a는 컴파일 상으로 기본형으로 들어갑니다. 스택에 들어가고
b는 기본형이 아닌 객체가 되어 특정 힙 동적 공간에 들어갑니다.
b라는 변수를 가리키는 스택에는 일종의 참조주소가 담겨져 있죠.
따라서, 서로 다른 참조주소를 가지기 때문에 a===b는 false입니다.
💻 코딩해 보세요!
▷이중 등호 비교와 삼중 등호 비교하기
section03폴더에 Alt+Insert누르고 Kotlin File을 만듭니다.
파일명은 ValRefCompare로 합니다.
package chap02.section03
fun main() {
val a: Int = 128
val b=a
}
변수 b의 경우에는 자료형을 추론해야 하기 때문에
그 줄을 블록 잡고, Ctrl+Shift+P를 누르면
Int형이라고 추론이 됩니다.
package chap02.section03
fun main() {
val a: Int = 128
val b: Double =a
}
이렇게 Double형으로 선언하는 경우
자료형 불일치 오류가 발생합니다.
package chap02.section03
fun main() {
val a: Int = 128
val b: Double =a.toDouble()
}
이렇게 오류가 난 경우에, 변환 메서드를 사용해서
val b: Double =a.toDouble()로 변환한다고 이야기 했었죠?
package chap02.section03
fun main() {
val a: Int = 128
val b = a
println(a==b)
println(a===b)
}
하지만 우리는 int형으로 추론되게끔 하기 위해서 b의 자료형 선언을 생략할 겁니다.
그럼 a==b로 먼저 값의 비교를 해볼까요?
실행 단축키 Shift+Alt+F10를 누르고, 2번을 클릭합니다.
결괏값이 true가 나오죠?
참조 주소의 비교도 true가 나옵니다.
package chap02.section03
fun main() {
val a: Int = 128
val b = a
val c: Int? = a
val d: Int? = a
val e: Int? = c
println(c==d)
println(c===d)
println(c===e)
}
먼저 변수 c와 d를 비교해보겠습니다.
값은 동일해서 true가 나왔지만 c와 d는 기본형이 아닌 객체가 되어서 동적공간에 존재하고,
c와 d에 들어있는 곳은 실제 스택에 특정 객체를 가리키는 주소가 됩니다.
128로 값이 같다고 할지라도 값만 같을 뿐 위치는 달라집니다.
그래서 false가 나옵니다.
다음으로 변수 c와 e를 비교해보겠습니다.
변수 c에서 동일하게 선언되어 있는 형태가
객체 참조형으로 되어있는 c로 선언이 되있고
e가 거기에 동일하게 c가 가리키고 있는 공간을 할당해서 가리키기 때문에
true가 나옵니다.
사실 저는 이렇게 말로 들으니 이해가 잘 안가더라고요. ㅠㅠ
이런 저의 마음을 선생님께서 아셨는지 그림으로 다시 설명해주셨습니다.
그림으로 정리해보겠습니다.
변수 a,b는 기본형이므로 Stack에 존재하고 주소가 아닌 값입니다.
하지만 변수 c,d,e는 Int? 형태로 선언했으므로 참조형입니다.
변수 c는 Heap이라는 동적 공간에 생성해서 담아놓게 됩니다.
변수 d는 또 다른 공간에 담아놓습니다.
값은 동일하지만 주소가 달라지기 때문에 둘의 참조주소는 다릅니다.
하지만 변수 e는 변수 c를 통해서 할당하게 되어
주소가 동일해서 변수 e는 변수 c의 주소를 담는 것과 같습니다.
즉, 같은 공간을 가리키기 때문에 서로 동일한 공간, 값을 갖게 됩니다.
다시 정리하자면,
null이 불가능한 형태는 기본형
null 가능한 형태는 참조형
꼭! 기억하세요!
참고
코틀린에서는 참조형으로 선언한 변수의 값이 –128~127 범위에 있으면 캐시에 그 값을 저장합니다.
즉, 특정 객체 공간에 할당하는 것 대신에 캐시에 담겨집니다.
캐시에 담겨진 경우에는 지정한 객체 생성 방식이 아니기 때문에
참조형에 대한 연산을 수행하면 다 같은 값이 나올 수 있습니다.
🔎 스마트 캐스트
▷구체적으로 명시되지 않은 자료형을 자동 변환
- 값에 따라 자료형을 결정
- Number형은 숫자를 저장하기 위한 특수한 자료형으로 스마트 캐스됨
만약 우리가 자료형을 선언하면 그 자료형으로 변수가 선언되어 만들어지죠?
하지만 자료형을 명시하지 않으면, 특정 자료형으로 자동변환해야 하는 경우가 생깁니다.
이럴 때는 대부분 컴파일러가 값에 따라 추론하고 있지만,
만약 특정 값이 어떤 값인지 몰라서 추론을 할 수 없는 경우에는
자료형을 명시해줘야 합니다.
그렇지 않으면 1은 정수형, 1.1은 실수형, 1L은 Long형 등의
우리가 특정 값을 정해줄 때, 규칙에 따라서 놓여주게 되면
컴파일러는 자동으로 결정하게 됩니다.
특정 자료형이 아닌 추상적인 자료형을 사용하는 경우에는
마음대로 바꿀 수 있습니다.
Number형은 Int, Long형 같은 다양한 수치를 가진 자료형을
상위로 가지는 자료형입니다.
Number형으로 선언하게 되면
하위의 어떤 숫자 타입으로도 변환할 수 있습니다.
💻 코딩해 보세요!
▷ 스마트 캐스트 사용해보기
사실 이 부분은 선생님께서 따로 같이 코딩실습하지 않으셨어요.
그래도 저는 해보겠습니다.
section03폴더에 Alt+Insert를 눌러 코틀린 파일을 만듭니다.
파일명은 SmartCast라고 임의로 지었습니다. (여러분은 다르게 지으셔도 돼요.)
package chap02.section03
fun main() {
var test: Number = 12.2
println("$test")
test = 12
println("$test")
test = 120L
println("$test")
test = 12.0f
println("$test")
/*test = "Hello"
println("$test")*/
//주석처리를 풀고 직접 확인해보시기 바랍니다.
}
실행 단축키 Shift+Alt+F10를 누르고, 2번을 클릭합니다.
12.2는 사실 Float형이죠 그래서 Float형으로 스마트 캐스트가 됩니다.
12일 때는 Int형으로 스마트 캐스트가 됩니다.
120L일 때는 Long형으로 스마트 캐스트가 됩니다.
12.0f일 때는 Float형으로 스마트 캐스트가 됩니다.
이렇게 스마트 캐스트는 필요에 따라서 값을 바꿀 수 있는 형태가 됩니다.
다만 Number은
예를 들어, test=“Hello”라고 값을 넣을 경우에는
"Hello"는 문자열형이고, 숫자 타입이 아니기 때문에 캐스트가 불가능합니다
💡 자료형의 검사
▷ is 키워드를 사용한 검사
변수 num은 값이 256이므로 정수형으로 추론될 수 있죠.
검사를 하고 싶을 때는, num is형을 사용해서 Int인지 검사를 합니다.
if (num is Int){
만약, Int형이면
print(num)
num을 출력하고
}else if (num !is Int){
num이 Int형이 아닐 경우에는
print("Not a Int")
}
Not a Int를 출력합니다.
이렇게 is 키워드를 사용해서 간단히 타입을 알 수 있습니다.
저는 또 간단하게 실습해보았습니다.
package chap02.section03
fun main() {
val num = 256L
if(num is Int){
print(num)
} else if(num !is Int){
print("Not a Int")
}
}
위의 사진처럼 변수 num의 자료형이 Int형일 경우에는
이렇게 변수 num을 출력합니다.
그런데 이렇게 변수 num에 Int가 아닌 자료형을 넣었을 때,
print("Not a Int")을 할 줄 알았는데...
오류가 뜨네요... 혹시나해서 같은 숫자형인 Long형을 해도 오류가 나오더라고요.
컴파일상에서 Int가 아닌 것을 감지하나봐요.
📸 묵시적 변환
▷ Any
자료형이 정해지지 않은 경우
모든 클래스의 뿌리 – Int나 String은 Any형의 자식 클래스이다.
Any는 언제든 필요한 자료형으로 자동 변환(스마트 캐스트)
Any형은 자료형이 정해지지 않은 경우입니다.
그래서 어떤 타입이라도 될 수 있는데요.
앞서 설명드렸던 Number라는 타입의 하부에는 Int, Long형 등의 숫자형 타입이 존재합니다.
이것을 다시 따라가보면 최상위에 Any타입이 있습니다.
모든 다양한 타입을 아우를 수 있습니다.
모든 클래스의 뿌리가 됩니다.
Int나 String은 Any형의 자식 클래스입니다.
그렇기 때문에 Any형으로 선언한 경우에는
어떠한 형으로든 변환할 수 있겠죠?
스마트 캐스트가 가능하다는 이야기입니다.
💻 코딩해 보세요!
▷ Any형 변수의 반환
Any타입으로 선언한 다음에 1로 초기화하면 정수형으로 스마트캐스트되고
20L으로 하면 Long형으로 스마트캐스트가 되고
“Hello”가 되어도 String형으로 스마트 캐스트가 될 수 있습니다.
a.javaClass를 하면 자바 기본형을 출력할 수 있습니다.
이것도 직접 실습해보았습니다.
package chap02.section03
fun main() {
var a:Any = 1
a = 20L
a = "Hello"
println("a: $a type: ${a.javaClass}")
}
이렇게 실습을 해보면 어떤 타입으로 값을 바꿔도 오류가 없음을 확인할 수 있습니다.
“Hello”가 되어도 String형으로 스마트 캐스트가 될 수 있습니다.
▷ Any형으로 인자를 받는 함수 만들기
매개변수 x를 Any 타입으로 선언한 경우에는
어떤 타입으로도 선언할 수 있습니다.
만약 String일 경우에는 println("x is String: $x")을 하고
Int인 경우에는 println("x is Int: $x")을 합니다.
실습 이번에도 간단히 해보았습니다.
package chap02.section03
fun main() {
checkArg("Hello")
checkArg(5)
}
fun checkArg(x: Any){
if (x is String){
println("x is String: $x")
}
if (x is Int){
println("x is Int: $x")
}
}
매개변수 x를 Any 타입으로 선언한 경우에는 어떤 타입으로도 선언할 수 있다는 것이 확인 가능하죠?
자, 이렇게 오늘도 마무리가 되었네요.
사실 점점 새로운 개념이 나와서 힘들지만
그래도 차근히 실습하면서 파악하고 있어요.
선생님께서 직접 실습하지 않으시고
설명만 하고 지나가시는 부분도
꼭 한 번 실습해보세요!
예상치 못한 오류에 당황하기도 하고
어떻게 해결해야 하는지 검색도 하고
그런 고군분투가 점점 쌓여서
우리에게 재산이 될테니까요.
강의 중간중간에 자막으로 주의할 점 나오는 점이 좋았어요.
자막 앞에 오리? 그림이 나오는 게 귀여워서
자주 나오길 은근 기대하고 있어요. ㅋㅋㅋ
이번 강의에는 선생님께서 그림으로 설명해주신 점이 인상깊었답니다.
기본형, 참조형 부분이 이해가 안갔었는데
자료화면의 그림으로 다시 설명해 주셔서
이해가 더 쉬웠습니다.
그리고 Any형은 직접 그림을 그려주셔서 이해하기가 쉬웠답니다.
중간중간 아기 목소리 나서 저는 좋았어요.
강의에 열심히 집중하고 있는
저에게 주는 작은 상 같아요. ㅎㅅㅎ
그럼 다음 시간에 만나요.
'CODING > 강의노트-부스트코스-코틀린' 카테고리의 다른 글
[부스트코스]📱코틀린 2-4 연산자를 조합해 다양한 식 만들기 (2) 비트연산자 (0) | 2021.02.04 |
---|---|
[부스트코스]📱코틀린 2-4 연산자를 조합해 다양한 식 만들기 (1) 기본연산자 (0) | 2021.01.29 |
[부스트코스]📱코틀린 2-2 나를 괴롭히는 널(Null)! (0) | 2021.01.27 |
[부스트코스]📱코틀린 2-1 기본 자료형과 변수 선언방법 (3) 크기 범위와 기타 자료형 (0) | 2021.01.22 |
[부스트코스]📱코틀린 2-1 기본 자료형과 변수 선언방법 (2) 정수형과 실수형 (0) | 2021.01.21 |