본문 바로가기
코틀린/개발자를 위한 코틀린 프로그래밍

[chapter06] 내장 자료형 알아보기

by 측면삼각근 2023. 8. 18.
728x90
반응형

들어가기 전에

본 포스팅은 개발자를 위한 코틀린 프로그래밍 의 chapter단위로 공부하고, 정리, 부족한 내용의 추가 학습내용을 정리하는 블로깅입니다.

이전 포스팅 ⬇️

[chapter05] 클래스 알아보기

 

[chapter05] 클래스 알아보기

들어가기 전에 본 포스팅은 개발자를 위한 코틀린 프로그래밍 의 chapter단위로 공부하고, 정리, 부족한 내용의 추가 학습내용을 정리하는 블로깅입니다. 이전 포스팅 ⬇️ [chapter04] 함수 알아보

messycode.tistory.com


01 내장 자료형 알아보기

클래스를 만들 때는 항상 기본적인 최상위 클래스가 필요하다.
코틀린에서는 최상위 클래스로 Any클래스를 제공한다. 이렇게 코틀린이 기본으로 제공하는 클래스를 내장자료형이라고 한다.

1.1 숫자 클래스

숫자 자료형의 최댓값과 최솟값

숫자 자료형의 크기는 1바이트부터 8바이트까지 다룬다.

  • Byte (1byte)
  • short (2byte)
  • Int, Float (4byte)
  • Long, Doubble (8byte)

숫자 클래스에서 최댓값은 MAX_VALUE, 최솟값은 MIN_VALUE이다.

println(Byte.MAX_VALUE) // 127
println(Byte.MIN_VALUE)  // -128
println(Short.MAX_VALUE) // 32767
println(Short.MIN_VALUE) // -32768
println(Int.MAX_VALUE) // 2147483647
println(Int.MIN_VALUE) // -2147483648
println(Long.MAX_VALUE) // 9223372036854775807
println(Long.MIN_VALUE) // -9223372036854775808
println(Float.MAX_VALUE) // 3.4028235E38
println(Float.MIN_VALUE) // 1.4E-45
println(Double.MAX_VALUE) // 1.7976931348623157E308
println(Double.MIN_VALUE) // 4.9E-324

숫자 클래스 멤버 알아보기

fun main() {
    fun Number.dir(): Set<String> {
        return this.javaClass.kotlin.members.map { it.name }.toSet()
    }

    fun Boolean.dir(): Set<String> {
        return this.javaClass.kotlin.members.map { it.name }.toSet()
    }

    println(1.dir()) 
    // [and, compareTo, dec, describeConstable, div, equals, inc, inv, minus, or, plus, rangeTo, rangeUntil, rem, resolveConstantDesc, shl, shr, times, toByte, toChar, toDouble, toFloat, toInt, toLong, toShort, toString, unaryMinus, unaryPlus, ushr, xor, hashCode]
    println(1.0.dir())
    // [compareTo, dec, describeConstable, div, equals, inc, minus, plus, rem, resolveConstantDesc, times, toByte, toChar, toDouble, toFloat, toInt, toLong, toShort, toString, unaryMinus, unaryPlus, hashCode]
    println(true.dir())
    // [and, compareTo, equals, not, or, toString, xor, hashCode]
    println(false.dir())
}

숫자 상속관계 및 클래스 관계 확인

  • superType 메서드로 클래스에서 상속한 모든 클래스를 확인할 수 있다.
  • Byte, Float, Double, Int 모두 Number Class를 상속받는다.
import kotlin.reflect.full.isSubclassOf

fun main() {
    fun<T> Number.isInstanceOf(compared:T):Boolean = when(compared){
        this.javaClass.kotlin, Number::class -> true
        else -> false
    }

    println(Int::class) // class kotlin.Int
    println(100.isInstanceOf(Number::class)) // true
    println(100.isInstanceOf(Int::class)) // true
    println((100).isInstanceOf(Int::class)) // true
    println((100)::class.isInstance(100)) // true

    // 클래스 상속 관계 확인 -> 클래스에서 상속한 모든 클래스를 확인할 수 있음
    println(((100)::class).supertypes) // [kotlin.Number, kotlin.Comparable<kotlin.Int>, java.io.Serializable]
    println(((100.1)::class).supertypes) // [kotlin.Number, kotlin.Comparable<kotlin.Double>, java.io.Serializable]
    println((Number::class).supertypes) // [kotlin.Any, java.io.Serializable]

    // 상속관계와 생성관계 확인
    val b= (100).toByte()
    println(b::class) // class kotlin.Byte
    println(b::class.supertypes) // [kotlin.Number, kotlin.Comparable<kotlin.Byte>, java.io.Serializable]
    println((b::class).isInstance(b)) // 인스턴스인지 확인: true
    println((b::class).isSubclassOf(Number::class)) // 상속관계 확인: true

    // Short, Float, Double, 모두 Number를 상속받음
}

NaN(not a number)

  • NaN은 계산도 비교도 안된다. (자기 자신과도 비교할 수 없다.)
  • 실수의 숫자를 정확히 모를 때는 무한대(INFINITY)를 사용한다.
fun main() {
    println(Double.NaN) // NaN
    println(Double.NaN == Double.NaN) // false
    
    println(Double.POSITIVE_INFINITY) // Infinity
    println(Double.NEGATIVE_INFINITY) // -Infinity
}

Nan인지 알기 위해서는 isNan을 사용하면 된다.

println(Double.NaN.isNaN()) // true

Any, Unit, Nothing 클래스

Any클래스

  • 클래스를 정의할 때 아무것도 상속하지 않아도 Any클래스는 자동으로 상속한다.
    그래서 이 클래스에 확장함수를 지정하면 공통 매서드로 사용된다.
  • 모든 클래스의 공통 메서드(Any의 메서드) equals, hashCode, toString메서드가 있다.
    • 이 클래스들은 모두 오버라이딩 하여 사용할 수 있다.

unit 클래스

  • 함수는 항상 반환값을 처리하는데, 보통 반환 값이 없다는 것은 Unit객체를 반환하는 것이다.
  • Unit클래스 또한 Any클래스를 상속하여 만들어진 것이다.

Nothing클래스

  • 함수를 반환할 때 아무것도 없다는 것을 표시하는 클래스가 nothing이다.
    • 보통 예외 등을 차리 할 때 이 클래스의 객체가 발생한 것으로 여긴다.
    • 이 삼수를 호출한 곳에서 try catch를 사용해서 예외를 잡고 예외의 메시지를 출력한다.
  • Nothing클래스 또한 Any클래스를 상속해서 만들어졌다.

배열 클래스로 배열 객체 생성 방법

보통 객체를 생성하는 팩토리 함수를 많이 이용한다.

fun main() {
    // Array(배열의 크기){람다 표현식}
    // 람다 표현식에서 it은 배열 크기의 인덱스 번호
    val arr = Array(5) { it * it }
    println(arr.contentToString()) // [0, 1, 4, 9, 16]

    // 특정 자료형에 맞도록 배열 생성
    val arrInt = IntArray(5) { it * 5 }
    println(arrInt.contentToString()) // [0, 5, 10, 15, 20]
    
    
    val arrNull = arrayOfNulls<Int>(5) // 널값을 가지는 배열 생성
    println(arrNull.contentToString())
}

02 자료형 처리 알아보기

2.1 널러블 여부

보톨 변수에 객체가 할당되지 않거나, null이 할당된 경우에 메서드나 연산자 등을 사용하면 널 포인터 예외가 발생한다.
이를 방지하려면 항상 널을 체크한 후에 연산자나 메서드 처리를 수행한다.

  • 기존 자료형에 물음표(?)를 붙이면 널을 처리할 수 있는 자료형이 만들어진다.
  • 널러블 자료형은 항상 널이 불가능한 자료형보다 상위 자료형이다.
  • 널에 대한 체크는 컴파일 타임에 확정하지만, 실제 실행할 때는 처리하지 않는다.
    그래서 널에 대한 처리는 전부 컴파일 처리할 때 예외를 발생시킨다.
  • 안전연산자(?.): 널 값이 들어오면 널로 처리하고, 널 값이 아니면 뒤에 오는 속성이나 메서드를 실행한다.
  • 엘비스 연산자(Elvis?:): 널 값이면 다음에 들어오는 값으로 변환한다.
  • 널 단언 연산자(!!): 널 값이 안들어온다고 확신할 경우만 사용. 널이 들어오면 예외가 발생된다.

2.2 타입 변환

특정 자료형 범위 내에서는 자료형을 변환 할 수 있다. 이를 타입변환(type conversion)이라고 한다.

타입 체크 및 변환 연산자

자료형에 대한 타입을 연산자로 확인한 후에는 타입이 자동으로 변환된다. 이것을 스마트 캐스팅(smart casting)이라고 한다.

  • 타입을 확인하는 연산자(is/!is): 상속관계에 해당하는 타입일때만 사용이 가능하다.
  • 타입을 변환하는 연산자(as/as?): 타입을 변환할 때도 상속관계 내에서 가능하고 불가능할 경우는 as?로 처리하면 null이 반환

2.4 자료형과 클래스

자료형으로 사용할 수 있는것

  • 클래스
  • 인터페이스
  • 추상클래스
  • 코틀린 object
  • 코틀린 함수 자료형
    • 코틀린에서는 함수 인터페이스를 리플렉션에서 제공한다. 문법으로 함수 자료형 표기법을 제공해서 쉽게 사용할 수 있다.
  • 코틀린 널러블 클래스

03 범위알아보기

일련된 숫자나 문자로 범위를 지정할 수 있는 컬랙션은 범위(Ranges)클래스이다. 실제 범위는 시작과 끝에 대한 정보를 속성에 가지고 있지만, 리스트처럼 모든 원소를 직접 가지고 있지는 않다.

이 범위로 특정 영역의 일련된 것을 처리 할 수 있다.

범위 클래스 맴버 확인

Int와 char, Long으로 만들어도 맴버가 모두 동일하다.

fun Any.dir():Set<String> = this.javaClass.kotlin.members.map { it.name }.toSet()

    println((1..5).dir())
    // [endExclusive, endInclusive, start, contains, equals, hashCode, isEmpty, toString, first, last, step, forEach, iterator, spliterator]
  • 범위 클래스에는 반복자(iterator)로 변환하는 메서드 iterator메서드가 있다. 이 메서드로 바로 이터레이터로 변환해서 순환문을 처리할 수 있다.
  • 내부 순환을 forEach로 할 수 있다.
  • step이 존재하여 단계를 넘어 갈 수 있다.
  • 역방향은 downTo로 순환할 수 있다.

문자열 범위

문자열도 범위를 지정할 수 있지만, 순환을 할 수 없다. 문자열로 범위를 지정하면 내부에 iterator메서드가 없다.

    val strR = ("문자열".."범위")
    /* iterator메서드가 없어 순환 할 수 없다.
    for(i in strR) {
        println(i)
    }
    */
    // For-loop range must have an 'iterator()' method

    fun ClosedRange<String>.info() =
        println("start: $start, endInclusive: $endInclusive")

    val closedRange: ClosedRange<String> = "문자열".."범위"
    closedRange.info() // start: 문자열, endInclusive: 범위

    println(closedRange.isEmpty()) // false
    println(closedRange.contains("문자열")) // true
    println("범위" in closedRange) // true

04 날짜(Date) 알아보기

    val today = Calendar.getInstance() // 캘린더로 현재 날짜와 시간을 가져온다.

    val year = today.get(Calendar.YEAR) // 년도
    val month = today.get(Calendar.MONTH) + 1 // 월: 0부터 시작하므로 +1
    val date = today.get(Calendar.DATE) // 일
    val hour = today.get(Calendar.HOUR_OF_DAY) // 시간
    val minute = today.get(Calendar.MINUTE) // 분
    val second = today.get(Calendar.SECOND) // 초

    println("Date: $year-$month-$date $hour:$minute:$second")

    // 날짜 포메팅 처리
    var arft = mapOf(
        "임의지정" to "yyyy년 MM월 dd일 HH시 mm분 ss초",
        "년월일" to "yyyy-MM-dd",
        "년월일시분초" to "yyyy-MM-dd HH:mm:ss",
        "년월일시분" to "yyyy-MM-dd HH:mm",
    )

    // 가장 간단한 날짜 포매팅은 SimpleDataForamt을 사용한다.
    var current = Date()
    for ((key, format) in arft) {
        var sdf = java.text.SimpleDateFormat(format) // 날짜 포메팅
        println("$key: ${sdf.format(current)}") // 포메팅된 날짜 출력
    }

     val long_now = System.currentTimeMillis() // 1970년 1월 1일 0시 0분 0초부터 현재까지의 시간을 밀리초로 반환
    println("1970년 1월 1일 0시 0분 0초부터 현재까지의 시간을 밀리초로 반환: $long_now") //  1692369589802

    // 밀리초를 날짜로 변환
    val t_date = Date(long_now)
    println("밀리초를 날짜로 변환: $t_date") // 포메팅 없이 그냥 출력하면 년월일 시분초가 나온다. > Fri Aug 18 23:39:49 KST 2023

    var sdf = SimpleDateFormat("yyyy-MM-dd HH:mm:ss") // 포매팅 처리
    println("포매팅 처리: ${sdf.format(t_date)}") // 포메팅된 날짜 출력 > 2023-08-18 23:39:49
반응형