[Android / Kotlin] 배열과 Array<Int> vs intArray

영서·2023년 7월 14일
0

Kotlin Basics

목록 보기
5/5

코틀린 문법을 공부하다가 배열이 좀 헷갈리는 것 같아서 정리하려 한다. 🧐

Array

코틀린의 배열은 Array 클래스로 표현한다.

Mac기준 command + 클릭으로 Array 클래스를 들여다보자.

public class Array<T> {
    public inline constructor(size: Int, init: (Int) -> T)

    public operator fun get(index: Int): T

    public operator fun set(index: Int, value: T): Unit

    public operator fun iterator(): Iterator<T>
}

코틀린에서 Array 클래스는 내부적으로 이렇게 구현되있는 것을 볼 수 있다.
이때, 코드를 보면 Array는 set() 으로 값을 변경할 순 있지만, 새로운 값을 넣거나, 혹은 삭제하는 함수는 없는 것으로 보인다. 다만 get() 을 이용하여 인덱스를 인자로 주어 값을 얻을 순 있는 것으로 보인다.

val ary: Array<Int> = Array(3, {1})
println("바꾸기 전 값: ${ary.get(2)} ")
ary.set(2, 5)
println("바꾼 값: ${ary.get(2)}")

// 바꾸기 전 값: 1 
// 바꾼 값: 5

위 코드를 작성해보면 3 개의 인덱스를 가진 Int형 Array 를 생성하여 그 값을 1 로 주었고, set()get() 을 사용하여 값을 바꾸고 그 결과를 확인한 것을 알 수 있다.

Array 특징

  • Array 는 생성한 순간, 사이즈는 고정되며 원소 삭제나 추가 등을 할 수 없다.
  • 대신 그 안에서의 원소 값 변경은 자유롭게 할 수 있음
  • set()get() 함수를 이용해도 되지만 대괄호[] 를 이용해서 배열의 데이터에 접근 가능
  • arrayOf 키워드를 통해 선언할 수 있음 (출력 시 java.util.Arrays.toString() 사용)
    -> java.util.Arrays.toString() 을 사용하지 않고 그대로 출력 시 주소값이 출력됨
val ary = intArrayOf(10, 20, 30)
println(ary)
    
// [I@7c30a502
  • 기본적으로 Mutable 동작을 한다. 따라서 val 으로 선언하나 var 으로 선언하나 똑같은 동작을 한다.
    -> 배열 안의 값이 변경된 것이지, 배열로 변경된 것이 아니기 때문이다.
val ary = intArrayOf(10, 20, 30)
ary[2] = 4
println(java.util.Arrays.toString(ary))

// [10, 20, 4]
  • 하지만, val 로 선언한 ary3ary2 를 저장하려고 하면 오류가 발생한다.
    -> 즉, 배열로 변경하려 하면 오류 발생
// var 로 선언
var ary2 = intArrayOf(1, 2, 3)
ary2[0] = 4
println(java.util.Arrays.toString(ary2))

// val로 선언
val ary3 = intArrayOf(4, 5, 6, 7, 8) // var로 선언하면 오류 발생하지 않음.
ary3 = ary2
println(java.util.Arrays.toString(ary3))

// Val cannot be reassigned
  • 서로 다른 타입 공존 가능
val c = arrayOf("Stirng", 1)
  • Array 를 합칠 수 있다.
val a = intArrayOf(1, 2, 4)
val b = intArrayOf(9, 3, 7)
val sumab = a + b
println(java.util.Arrays.toString(sumab))

// [1, 2, 4, 9, 3, 7]

Array<Int>intArrayOf() 의 차이점

-> 위 코드의 배열을 합치려고 하는 과정에서 한 가지 의문이 발생했었다. intArrayOf() 로 생성한 것과 Array<Int> 는 똑같은 타입이니까 더하는 것이 되겠지 싶었다. 하지만, 더하는 과정에서 서로 타입이 맞지 않아 더하는 것이 되지 않는 오류가 발생했다.

val ary4 = intArrayOf(4, 5, 6, 7, 8)
val ary5: Array<Int> = arrayOf(4, 0, 5)
val sumAry = ary4 + ary5 // 오류 발생
println(java.util.Arrays.toString(sumAry))

그 이유는 Array<T>참조형 자료형(객체)를 데이터의 요소로 가지고, IntArray 와 같은 기본 참조형 array는 기본형을 데이터의 요소로 가지기 때문이다.

즉, IntArray 와 같은 array 타입은 Primitive type이고, 이걸 사용하면 Boxing Overhead 를 피할 수 있다.
또한 Array 클래스와 상속관계는 없지만, 메소드나 프로퍼티는 동일하다고 코틀린 공식 문서에서도 나와있다.

조금 어렵다면, 자바의 박싱, 언박싱 개념을 알면 Array<Int> 는 자바의 Integer[] 와 매핑되고, IntArray 는 자바의 int[] 에 매핑되기 때문에 Overhead 방지를 위해 꼭 구분지어 사용해야 한다는 것을 알 수 있다.

TMI 🤔

오늘 처음으로 공식문서를 읽기도 하고 안드로이드 스튜디오 내부적으로 구현된 파일도 읽다보니 도움이 많이 되는 것 같다.
그리고 박싱 오버헤드 없이 쓸 수 있다는 건 시간복잡도를 생각해야하는 코테에서도 유용하다고 생각되기 때문에 나중에 비교하려고 한다!

Reference📚

참고자료:
https://kotlinlang.org/docs/arrays.html
https://velog.io/@haero_kim/List-%EB%9E%91-Array-..-%EB%8C%80%EC%B2%B4-%EB%AC%B4%EC%8A%A8-%EC%B0%A8%EC%9D%B4%EC%95%BC#%EC%A0%95%EC%A0%81-%EB%8D%B0%EC%9D%B4%ED%84%B0-%ED%83%80%EC%9E%85-array

profile
Let it rip

0개의 댓글