Kotlin

Pardess·2025년 4월 24일

Kotlin의 기본 타입(Primitive Types 또는 Built-in Types)은 다른 언어들처럼 숫자, 문자, 불리언 등 자주 사용하는 데이터 타입들을 제공하지만, Kotlin에서는 이들을 모두 객체(클래스) 로 다룬다는 점이 특징입니다. Kotlin은 자바와 달리 모두가 객체로 취급되지만, 실제로는 JVM이 primitive로 최적화해서 컴파일합니다. 즉 스택에 할당됨.

1. 기본 타입 (Primitive Type)

Kotlin 타입설명JVM 타입 (컴파일 시)
Byte8비트 정수byte
Short16비트 정수short
Int32비트 정수int
Long64비트 정수long
Float32비트 부동소수점float
Double64비트 부동소수점double
Char문자 (16비트)char
Booleantrue / falseboolean

2. 문자 타입 (Char)

  • 단일 문자 표현: 'A', '1', '#'
  • Char는 숫자가 아닌 문자형 클래스임.
  • == 으로 비교 가능, 유니코드 값 기반 연산도 가능

3. 문자열 (String)

  • String은 불변(immutable) 객체
  • 여러 문자로 이루어진 객체
  • + 연산자나 $변수 를 이용한 문자열 템플릿 지원
  • 문자열 리터럴은 "상수 풀(String Pool)"에 저장됨

val String 은 String Constant Pool 이라는 특수 영역에 저장하므로, 동일한 값이 있으면 재사용

print(a === b) // true

→ 힙에 있는 게 아니라, 클래스 로더에 의해 관리되는 상수 풀에 존재

StringBuilder 사용 (성능 최적화)

  • StringBuilder는 내부에서 하나의 버퍼를 유지하며 문자열을 조립
  • 많은 문자열 연결 시 가장 좋은 방법

문자열 리터럴 vs 동적 문자열

  • "Hello" → 상수 풀(String Constant Pool)에 저장됨 → 재사용 가능 → 메모리 효율적
  • "Hel" + "lo" → 컴파일 타임 연산이므로 상수 풀
  • "Hel" + name → 런타임 연산 → 힙에 새 문자열 생성

JVM은 동일한 문자열 리터럴을 재사용하기 위해 String Pool을 운영하며, "Hello" 같은 리터럴은 메모리 최적화를 위해 같은 인스턴스로 공유됩니다.

항목StringStringBuilder
변경 가능성❌ 불변 (immutable)✅ 가변 (mutable)
연산 방식새 객체 생성내부 char[]에 append
속도느림 (많은 객체 생성)빠름 (메모리 재사용)

String은 불변이기 때문에 덧셈 시마다 새로운 객체가 생성되며,

문자열 조작이 많을 때는 StringBuilder를 사용하면 성능이 크게 향상됩니다.

4. 불리언 타입 (Boolean)

  • true, false 만 가짐

5. 배열 (Array)

  • 고정 크기의 배열, arrayOf() 함수로 생성
  • 요소 접근: arr[index] 또는 arr.get(index)
  • 변경: arr[index] = value 또는 arr.set(index, value)

6. Any, Unit, Nothing

타입설명
Any모든 Kotlin 클래스의 최상위 타입 (자바의 Object)
Unit반환 값이 없는 함수의 리턴 타입 (자바의 void와 유사)
Nothing절대 반환되지 않음을 명시하는 타입 (예: 예외 던짐)
Kotlin 표현JVM 타입박싱 여부성능
Intint❌ 박싱 안 됨매우 빠름
Int?Integer✅ 박싱됨느림 (GC 부담)

Int vs Int?

Kotlin에서는 Intnullable하지 않은 원시 타입, Int?nullable이 가능한 박싱 타입입니다.

Kotlin 타입JVM에서 컴파일되는 타입특징
Intintprimitive, 성능 좋음
Int?java.lang.Integernullable, 박싱됨, 성능 저하 가능

Boxing이란?

Primitive 타입(예: int, double)을 객체 타입(예: Integer, Double)으로 감싸는 것

즉, 숫자 값처럼 단순한 데이터를 객체로 래핑(wrapping) 하는 거야.

  • Int?에 담기면 자동으로 객체로 박싱됨.
  • 이 객체는 힙(Heap) 메모리에 저장되고, 참조를 통해 접근돼.

Unboxing이란?

객체 타입에서 원시 타입 값을 꺼내는 것

왜 필요한가요?

JVM에는 원래 두 가지 타입이 있어요:

종류예시저장 위치특징
Primitiveint, double, boolean스택작고 빠름, 객체 아님
Object (Wrapper)Integer, Double, Booleannull 가능, 제네릭에서 사용 가능

주의: 박싱은 성능 비용이 발생합니다

비용 원인설명
힙 할당객체 생성 비용 (GC 부하 포함)
equals 비교== → 참조 비교, .equals() → 값 비교 차이
null 처리primitive는 null 불가 → wrapper 사용 시 null 처리 가능하지만 주의 필요

언제 boxing이 일어날까?

상황boxing 발생 여부
제네릭 타입에 전달✅ (제네릭은 primitive 허용 안 함)
Any, Object로 업캐스팅
List 등 컬렉션 사용✅ (List는 객체만 저장 가능)
단순 연산 (a + b 등)❌ (primitive 연산)

클래스

주 생성자 (Primary Constructor)

  • 클래스 선언과 함께 괄호에 선언된 생성자
class Dog(val name: String)

보조 생성자 (Secondary Constructor)

  • constructor 키워드로 선언, 주 생성자 호출 필요
class Animal(val name: String) {
    var age: Int = 0

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

초기화 블록 (init block)

init 블록은 주생성자의 파라미터를 이용한 초기화 코드를 작성하는 곳입니다.

클래스 상속

Kotlin의 클래스는 기본적으로 final상속 불가 → 상속을 허용하려면 open 키워드 사용해야 함

추상 클래스 (Abstract Class)

  • 추상 클래스는 구현을 강제하는 메서드 포함 가능
  • 인스턴스화 불가능

인터페이스 (Interface)

  • 다중 상속 가능
  • 구현/비구현 함수 모두 가능
항목가능 여부설명
val / var 프로퍼티 선언반드시 구현 클래스에서 초기화하거나, getter만 정의
backing field 사용 (field 키워드 등)인터페이스는 저장공간이 없음
초기값 있는 변수 선언 (var count = 0)초기값 저장 불가

abstract class 사용 시기

  • 상태(필드)나 생성자가 필요할 때
  • 공통 기능(메서드) 외에도 공통 속성이 있는 클래스들을 만들고 싶을 때
  • 한 클래스만 상속받아도 충분할 때

interface 사용 시기

  • 어떤 클래스에 기능만 부여하고 싶을 때 (예: Serializable, Clickable)
  • 다중 상속이 필요한 경우
  • 상태 없이 행동(기능)만 정의할 때
  • 유연한 설계가 필요한 경우
항목class Hi(val name: String)class Hi(name: String)
프로퍼티 생성
외부 접근 가능 (hi.name)
내부 메서드에서 사용
메모리에 저장됨✅ (프로퍼티)❌ (파라미터일 뿐)

class Hi(val name: String)

  • name생성자 매개변수이자, 클래스의 프로퍼티(멤버 변수)가 됩니다.
  • 외부에서 hi.name처럼 접근할 수 있어요.

class Hi(name: String)

  • name은 단순히 생성자 매개변수일 뿐, 클래스 내부에 저장되지 않음.
  • 외부에서는 hi.name처럼 접근할 수 없어요.

Object

"딱 한 번만 생성되는 객체(싱글턴)"를 선언하고 즉시 사용할 수 있게 해주는 키워드

✅ 주요 특징 정리

특징설명
자동 싱글턴클래스처럼 여러 번 생성되지 않고 한 번만 생성됨
인스턴스화 필요 없음바로 이름.함수() 형태로 사용
상태(state) 저장 가능내부에 val, var, 함수 등 자유롭게 정의 가능
thread-safeKotlin이 보장하는 thread-safe 싱글턴 객체
생성자 없음constructor 사용 불가

object의 다양한 활용

1. 싱글턴 패턴

object Config {
    val version = "1.0.0"
    fun printVersion() {
        println("App Version: $version")
    }
}

2. 객체 표현식 (object : 인터페이스)

val listener = object : View.OnClickListener {
    override fun onClick(v: View?) {
        println("Clicked!")
    }
}

→ 일회성으로 사용할 객체를 정의하고 바로 사용

  • 일회성으로 익명 객체(anonymous object) 를 생성할 때 사용
  • 특정 인터페이스 구현 혹은 클래스를 상속하여 바로 객체 생성

3. companion object (정적 멤버처럼 사용)

class MyClass {
    companion object {
        val TAG = "MyClass"
        fun log(message: String) {
            println("[$TAG] $message")
        }
    }
}

object, companion object 는 GC 대상이 아님

Sealed class

클래스의 하위 타입 정의를 제한하여, 컴파일러가 모든 하위 클래스를 인식할 수 있도록 해주는 클래스

  • 상속은 가능하지만, 같은 파일 내에서만 허용됨
  • 덕분에 when 분기물에서 컴파일러가 모든 경우를 체크할 수 있음.
  • 정해진 개수의 타입만을 허용하는 클래스 계층을 만들기 위한 구조

sealed class vs abstract class vs enum

항목sealed classabstract classenum class
상속 가능✅ (같은 파일 내만)✅ (어디서든 가능)
타입 제한✅ (고정된 값만 가능)
when 분기 완전성 체크
목적타입 분기 안전성공통 로직 제공고정 값 나열
값 포함다양한 타입/데이터 가능가능제한적

Data Class

데이터를 담기 위한 클래스를 간결하게 정의할 수 있도록 만들어진 Kotlin의 특수한 클래스입니다.

data class가 자동으로 생성해주는 것

메서드역할
equals()두 객체의 내용이 같은지 비교
hashCode()해시 값 생성 (Map, Set에서 사용됨)
toString()객체 내용을 문자열로 표현
copy()동일한 객체를 복사하면서 일부 값만 변경 가능
componentN()component1(), component2() → 구조 분해 선언에 사용

일반 클래스와 비교

class NormalUser(val name: String, val age: Int)
val a = NormalUser("Polaris", 28)
val b = NormalUser("Polaris", 28)

println(a == b)  // false (참조 비교)

→ 일반 클래스는 equals()를 override하지 않으면 참조 주소로 비교

data class는 내용이 같으면 자동으로 같다고 판단

얕은 복사(Shallow Copy)란?(data class.copy()

객체를 복사하되, 내부에 포함된 참조형 객체는 복사하지 않고 참조만 공유하는 복사

깊은 복사(Deep Copy)란?

객체를 복사하면서, 내부에 포함된 참조형 객체까지 모두 새로 복사하는 방식

구분얕은 복사 (copy())깊은 복사 (직접 구현)
기본 제공 여부Kotlin의 copy()는 기본으로 제공직접 수동 구현 필요
참조형 필드공유됨 (같은 주소)별도 객체로 새로 복사됨
안전성간편하지만 위험할 수 있음안전하지만 구현 비용 있음
활용도일반적인 UI 상태에 적합완전한 복제가 필요한 로직에 적합

Kotlin에서 abstract classinterface는 모두 다형성과 추상화를 제공하는 구조지만,

용도와 기능, 설계 의도에서 차이점이 뚜렷합니다.

공통점부터 말씀드리면,

두 구조 모두 구현이 없는 함수(추상 메서드)를 정의하여

서브 클래스가 해당 함수를 반드시 구현하도록 강제

할 수 있고,

Kotlin에서는 둘 다 기본 구현(default body)도 포함할 수 있습니다.

하지만 주요 차이점은 다음과 같습니다.

  • 상태 보유 여부 abstract class는 생성자와 필드를 가질 수 있어 상태를 보유할 수 있지만, interfacebacking field가 없기 때문에 상태를 저장할 수 없습니다. 선언된 프로퍼티는 항상 구현 클래스에서 override되거나, 커스텀 getter로 제공되어야 합니다.
  • 상속 구조 Kotlin은 클래스는 하나만 상속 가능하지만, 인터페이스는 여러 개 구현할 수 있기 때문에 다중 상속이 가능합니다. 따라서 다양한 역할을 조합할 때는 interface가 더 유연합니다.
  • 용도 차이 abstract class"공통된 상태와 동작을 묶어 하나의 기반 클래스를 제공"하는 데 적합하며, interface"특정 기능(역할)을 선언하고 구현하도록 강제"하는 데 적합합니다.

Android에서 View 처럼 공통 속성과 메서드를 가진 기본 뷰 클래스는 abstract class 로,

반면에 OnClickListener 처럼 기능을 부여하는 형태의 객체는 interface로 구현됩니다.

  • 공통 구현 + 상태 공유가 필요하다면 → abstract class,
  • 행동(역할)만 부여하거나 다중 구현이 필요하다면 → interface가 적합합니다.

Const val 이란?

컴파일 타임에 결정되는 상수(Constant Value)를 정의할 때 사용

즉, 코드가 컴파일되는 순간 값이 확정되어 있어야 함

const val vs val 차이

항목const valval
상수 여부컴파일 타임 상수런타임 상수
사용 위치top-level, object, companion object어디서든 가능
초기화 시점컴파일 시런타임 시
초기화 값 조건리터럴만 가능 (String, Int, 등)계산된 값도 가능
성능매우 빠름 (코드에 삽입됨)접근 시 메모리 읽기 필요
  • const는 반드시 top-level, object, companion object 내부에서만 사용 가능
  • 함수 내부, 클래스 내부에는 직접 사용할 수 없음
키워드용도초기화 시점위치 제한성능
val변경 불가능한 변수런타임어디든 가능일반
const val컴파일 타임 상수컴파일 시top-level 또는 object 내부빠름

지역 초기화와 위임

Kotlin에서는 객체가 실제로 필요할 때까지 초기화를 미루는 방식을 제공해요. 대표적으로:

  • lateinit: var에 대해, 초기화를 나중에 할 수 있게 함
  • lazy: val에 대해, 처음 접근 시에만 초기화하고 값을 저장

언제 뭐 써야 할까?

상황추천 방식
초기화 순서를 나중으로 미루고 싶음lateinit
처음 한 번만 초기화하고 캐싱하고 싶음by lazy

Primitive 타입을 lateinit 하고 싶다면

Delegates.notNull() 사용
변수 초기화 전 접근하면 IllegalStateException을 발생시킵니다.

var number: Int by Delegates.notNull()

컬렉션과 반복

타입설명중복 허용순서 유지
List순차적 요소 모음✅ 가능✅ 유지
Set중복 없는 요소 집합❌ 불가❌ 기본은 없음 (LinkedHashSet 예외)
Map키-값 쌍 저장✅ (키는 중복 불가)✅ 유지 (LinkedHashMap 사용 시)

Kotlin에서의 ==, ===, .equals() 차이

표현의미Java에서 대응설명
==값 비교.equals()Kotlin은 자동으로 .equals() 호출
===참조 비교==동일한 객체인지 주소값 비교
.equals()값 비교.equals()수동 호출

📌 박싱(Boxing)이 왜 문제인가?

기본형 Int, Double은 값 비교가 빠릅니다 (primitive → CPU 비교)

하지만 박싱된 Integer, Double은 객체이므로 equals() 호출 + 널 체크 + 타입 체크가 추가됩니다.

결론 (면접용 요약)

Kotlin에서 ==는 값 비교이지만, Boxing이 발생하면 .equals() 호출로 인해 성능 저하가 있을 수 있습니다.

특히 반복문, 컬렉션 내 비교에서 Boxed 타입이면 불필요한 객체 생성과 함수 호출이 발생하므로 주의해야 합니다.

Kotlin에서 List<Int> vs IntArray 성능 비교 및 최적화

Kotlin의 List는 내부적으로 박싱된 Integer 객체이기 때문에, 반복, 연산, 비교 시 불필요한 GC 및 성능 저하가 발생할 수 있습니다.

반대로 IntArray는 primitive 기반 배열로, 메모리 효율과 속도 면에서 훨씬 뛰어납니다.

대량 처리/성능이 중요한 경우엔 항상 IntArray를 사용하는 것이 좋습니다.

Scope 함수 패턴

let

수신 객체: it

반환 값: 람다의 마지막 표현식

주 용도: null-safe 처리, 임시 범위 생성, 체이닝

run

수신 객체: this

반환 값: 람다의 마지막 표현식

주 용도: 객체 초기화 + 결과 반환

with

수신 객체: this

반환 값: 람다의 마지막 표현식

주 용도: 외부 객체 설정

apply

수신 객체: this

반환 값: 수신 객체 자신

주 용도: 객체 설정(builder 패턴)

also

수신 객체: it

반환 값: 수신 객체 자신

주 용도: 부수 효과(side effect), 디버깅, 로깅

스마트 캐스트

Kotlin에서 is 연산자 또는 null-check 등을 사용한 후,

컴파일러가 자동으로 명확한 타입으로 캐스팅(cast)해주는 기능입니다.

타입 추론 (Type Inference)

Kotlin은 변수 선언 시 타입을 생략해도 컴파일러가 자동으로 타입을 유추합니다.

접근 제어자

Modifier클래스 외부 접근서브클래스 접근같은 파일 내부모듈 내
public
internal
protected
private

Kotlin은 스마트 캐스트와 타입 추론을 통해 불필요한 형변환과 타입 선언을 줄이고,

코드의 간결성과 안정성을 동시에 제공합니다.

또한 private, internal, protected, public의 가시성 제어를 통해

클래스, 함수, 프로퍼티 수준에서 모듈 안전성과 캡슐화를 유지할 수 있도록 설계되어 있습니다.

주요 특수 타입

Any

모든 클래스의 최상위 타입

Any?

모든 nullable 타입의 최상위 타입

Unit

반환값이 없음을 의미

Nothing

절대 반환하지 않음 (예외 등)

Enum class

  • 값이 고정된 상수 집합
  • 각 항목은 싱글턴 객체
  • 속성, 함수 추가 가능

Sealed class

  • 컴타임 시점에 하위 클래스가 제한된 계층
  • 데이터를 가질 수 있는 다양한 타입 표현 가능
  • when 에서 모든 하위 클래스 분기 시 컴파일러가 체크
항목enum classsealed class
상속❌ 불가능✅ 하위 클래스 가능
상태 데이터거의 없음✅ 다양한 상태/필드 표현 가능
하위 타입 제한✅ 고정된 값✅ 같은 파일 내 클래스만 허용
활용 사례상태 상수, 타입 식별자결과 표현, UI 상태 등
예시Direction, LogLevelSuccess/Failure, UIState

초기화

키워드 / 방식대상초기화 시점특징
val불변 변수선언 시재할당 불가
var가변 변수선언 시값 변경 가능
lateinitvar only나중에 수동 초기화nullable 없이 지연 초기화
by lazyval only최초 접근 시1회 초기화 + 캐싱
init 블록클래스주 생성자 실행 직후생성자 파라미터 기반 초기화
보조 생성자클래스별도 constructor() 호출반드시 this(...)로 주생성자 호출 필요

제네릭

클래스나 함수에서 사용할 데이터의 타입을 나중에 타입 파라미터(T)로 일반화하여 여러 타입에 대해 재사용 가능하게 만드는 문법입니다.

장점

  • 타입 안정성 향상: 컴파일 타임에 타입 오류를 방지
  • 재사용성 증가: 하나의 클래스/함수로 다양한 타입 처리 가능
  • 불필요한 캐스팅 제거: 타입 추론으로 명확한 타입 반환

out (공변성: Produces)

out T: T 를 밖으로 반환하고, 넣지 않음

읽기 전용, 생산자 적할

in (반공변성: Consumes)

in T: T 를 받기만 하고, 반환하지 않음

쓰기 전용, 소비자 역할

고차함수

  1. 함수를 인자로 받거나
  2. 함수를 반환하는 함수를 말합니다.

인라인 고차 함수의 성능

  • 고차 함수는 기본적으로 람다 객체 생성 + invoke() 호출 오버헤드가 있음
  • inline 키워드를 붙이면 호출 지점에 함수 본문을 복사(inline) -> 오버헤드 제거

reified 타입 파라미터

제네릭 타입 T의 타입 정보를 런타임에도 사용하고 싶을 때

inline fun <reified T> Gson.fromJson(json: String): T {
    return this.fromJson(json, T::class.java)
}

// 사용
val user: User = gson.fromJson(jsonString)

inline을 안쓰는 경우

  • 람다 파라미터가 아주 많거나, 복잡한 로직을 담고 있어 코드 복사 비용이 클때
  • 함수 본문이 방대한 경우 인라인 시 바이너리 사이즈가 눈에 띄게 늘어날 때
  • 디버깅이 중요한 상황에서 스택 트레이스를 명확히 유지하고 싶을 때

noinline

  • inline 함수 안에 있는 람다 중 인라인되지 말아야 할 파라미터에 붙임
  • 예: 캐싱이나 컬렉션 등에 람다를 저장해야 할 때

crossline

  • 람다 내부의 비지역 반환을 금지하고 싶을 때 사용
  • 주로 함수를 다른 스코프로 넘겨줄 때 안전성 확보용

Kotlin의 기본 자료형(Primitive Type)은 어떻게 처리되나요?

Kotlin에서는 기본 자료형도 모두 객체처럼 다룰 수 있는 클래스입니다. 하지만 JVM 상에서는 자동으로 Java의 primitive 타입으로 최적화됩니다.

Kotlin에서 val과 var의 차이는 무엇인가요?

💡 val은 immutable 참조, var는 mutable 참조입니다.

Kotlin의 data class는 어떤 목적이고, 어떤 메서드를 자동 생성하나요?

data class데이터 보관용 클래스로, 값을 비교하거나 복사하는 기능이 필요한 경우 사용됩니다.

자동 생성되는 메서드

  • equals(), hashCode()
  • toString()
  • copy()
  • componentN() (Destructuring)

Kotlin에서 ==와 ===의 차이는 무엇인가요?

연산자의미비교 대상
==값 비교equals() 호출
===참조 비교객체 주소가 같은지 확인

Kotlin에서 lateinit과 by lazy의 차이를 설명해 주세요.

항목lateinitby lazy
용도나중에 초기화할 수 있는 var처음 사용 시 초기화되는 val
대상var + non-null 객체만 가능val + 지연 초기화가 필요한 값
초기화 시점명시적으로 나중에 초기화최초 접근 시 자동 초기화
Null 허용✅ 가능
사용 위치클래스 멤버클래스 멤버, 전역 변수, 객체 등

lateinit은 주로 Android에서 ViewModel, ViewBinding 등에 사용되고,
by lazy는 비용이 큰 객체를 나중에 초기화할 때 사용합니다.

Kotlin의 object, companion object, singleton의 차이를 설명해 주세요.

object - 즉시 생성되는 싱글톤 객체

companion object - 클래스 내부의 정적 객체

Kotlin에서 object는 자체적으로 싱글톤 객체를 생성하는 키워드로, 전역 유틸성 객체에 자주 사용됩니다.

반면 companion object는 클래스 내부의 정적 객체로, Java의 static 대체 용도로 활용되며 클래스 로딩 시 한 번만 생성됩니다.

디자인 패턴으로서 Singleton은 오직 하나의 인스턴스를 갖는 객체를 의미하며, Kotlin에서는 object를 통해 이 패턴을 언어 차원에서 간결하게 구현할 수 있습니다.

sealed classenum class의 차이와 용도는?

  • 고정된 타입 집합을 표현합니다.
  • when 표현식에서 모든 하위 타입을 컴파일 타임에 체크 가능

in, out, reified 키워드를 제네릭에서 사용할 때 각각 어떤 의미인가요?

enum class는 고정된 상수 집합을 표현할 때 사용하며, 각 항목은 데이터 없이 단일한 상태로 존재합니다. 반면 sealed class는 상속 가능한 클래스 계층을 표현하며, 각 하위 클래스는 서로 다른 형태의 데이터를 가질 수 있습니다.

enum은 대표적으로 방향, 성별, 로그 레벨 등 단순 상태 구분에 사용하고, sealed class는 UI 상태, 네트워크 응답 등 다양한 데이터 구조와 함께 분기 처리가 필요한 곳에 사용합니다.

또한 sealed classwhen 구문에서 컴파일 타임에 exhaustive 체크가 가능해, 더 안전한 상태 분기 처리가 가능합니다.

Kotlin에서 Int, Boolean 등은 실제로 객체로 할당되나요? → boxing/unboxing 설명

Kotlin에서 Int, Boolean 등은 문법적으로는 클래스처럼 사용되지만, 컴파일 시에는 JVM의 primitive 타입으로 최적화되어 할당됩니다.

단, 이 타입들이 nullable (Int?, Boolean?)로 사용되거나 제네릭에 전달되면 JVM에서는 해당 타입을 객체(Integer, Boolean)로 boxing하여 처리하게 됩니다.

이때 발생하는 추가 객체 할당이나 equals 비교, GC 비용 등이 성능 저하 요인이 될 수 있습니다.

따라서 실무에서는 가능한 한 primitive 타입을 유지하고, 컬렉션에서는 IntArray, BooleanArray 등을 사용하여 boxing을 피하는 것이 성능적으로 유리합니다.

List<Int>IntArray의 성능 차이는 왜 발생하나요?

List는 내부적으로 Integer 객체의 리스트이기 때문에, 각 요소가 박싱된 객체로 메모리에 저장됩니다.

반면 IntArray는 JVM의 primitive 배열(int[])로 컴파일되어 각 요소가 primitive로 메모리상에 연속 배치됩니다.

이로 인해 IntArray메모리 할당, 캐시 적중률, 연산 속도 면에서 List<Int>보다 훨씬 효율적입니다.

반복이 많은 숫자 처리나 퍼포먼스가 중요한 연산에서는 List<Int> 대신 IntArray를 사용하는 것이 좋습니다.

String은 불변 객체인데 성능 최적화는 어떻게 하나요?

Kotlin의 String은 Java와 동일하게 immutable이며, 변경 시마다 새로운 객체가 생성됩니다.

이로 인해 문자열 조작이 많은 경우에는 매번 메모리를 새로 할당하게 되며, GC 부담도 커질 수 있습니다.

성능 최적화를 위해 Kotlin에서는 StringBuilder를 사용하여 mutable한 방식으로 문자열을 누적하고, 최종적으로 toString()을 호출하여 String으로 변환합니다.

또한 문자열 리터럴은 JVM의 String Constant Pool에 저장되어 중복 없이 재사용되어, 비교 연산(===) 시에도 성능 이점이 있습니다.

const val 에 대해서 설명해주세요.

const val은 컴파일 타임 상수(Constant)를 선언할 때 사용하는 키워드입니다.

일반적인 val은 런타임에 초기화되는 불변 값이지만, const val은 컴파일 시점에 값이 결정되어

바이트코드에 바로 삽입되므로 더 빠르고 효율적입니다.

사용 조건

  • String, Int, Doubleprimitive 또는 String 리터럴만 가능
  • top-level, object, 또는 companion object 안에서만 사용 가능
  • 함수나 클래스 내부에서는 사용할 수 없습니다

람다에서 it, this는 각각 어떤 의미인가요?

it: 전달된 값 (매개변수 인자), let, also, filter, map 등

this: 람다 내부의 수신 객체, apply, run, with 등

hashCode()는 무엇인가요?

hashCode()는 객체의 고유 식별값을 표현하는 해시 함수로, 컬렉션에서 객체를 빠르게 찾거나 비교할 때 중요한 역할을 합니다.

항목equals()hashCode()
목적논리적 동등성 판단해시 기반 컬렉션에서 탐색/분류
반환값true / false정수 (Int)
기준필드 값 비교정수 연산으로 계산된 값
용도객체 내용 비교컬렉션 검색, 중복 체크 등
관계equals()가 같으면 hashCode()도 같아야 함반대는 아님 (충돌 허용)

0개의 댓글