with ChatGPT 시리즈는 ChatGPT의 내용과 개인의 생각을 토대로 학습해 보는 컨텐츠입니다.
Kotlin은 정적 (static) 멤버가 존재하지 않는 대신, object를 통한 싱글턴 객체 개념을 제공합니다.
또한 Java의 static과 비슷한 역할을 하는 companion object도 함께 지원합니다.
이번 글에서는 다음 내용을 중심으로 살펴보겠습니다.
- Kotlin의 object 키워드란?
- object를 사용하는 대표적인 상황
- companion object의 개념과 특징
- 자바의 static과의 비교
- 실무에서의 활용 예시
🔹 1. object 키워드란?
Kotlin의 object 키워드는 클래스의 인스턴스를 하나만 생성하는 싱글턴 선언 방식입니다.
✅ 싱글턴 객체 정의
object AppConfig {
val version = "1.0.0"
fun printVersion() {
println("App version: $version")
}
}
- AppConfig는 프로그램 전체에서 단 하나의 인스턴스만 존재함
- 즉, Java에서 private static final INSTANCE = new AppConfig()와 동일한 구조
- 별도 인스턴스 생성 없이 바로 사용 가능 (ex: AppConfig.printVersion())
🔹 2. object를 사용하는 대표적인 상황
상황 | 예시 | 이유 |
설정값, 전역 상수 관리 | object Config | 싱글턴 객체로 한 번만 생성되면 됨 |
유틸리티 함수 모음 | object Utils | Java의 static 유틸리티 클래스 대체 |
상태 없는 전략 객체 | object StrategyImpl | 동일 인스턴스를 재사용 |
🔹 3. companion object: 클래스 내부 정적 멤버
Kotlin은 Java처럼 static 키워드가 없기 때문에, 클래스에 정적 (static)처럼 작동하는 멤버를 만들고 싶을 때는 companion object를 사용합니다.
class User(val name: String) {
companion object {
fun createDefault(): User = User("Guest")
}
}
val user = User.createDefault()
- createDefault()는 마치 정적 메서드처럼 사용할 수 있음
- 내부적으로는 User.Companion.createDefault()로 동작하지만, Kotlin에서는 생략 가능
✅ companion object는 실제 객체다
즉, 단순한 정적 멤버 모음이 아니라 클래스 내부에 선언된 하나의 객체입니다.
그래서 인터페이스 구현, 상속 등 객체로서의 동작도 가능합니다.
interface Factory<T> {
fun create(): T
}
class Order(val id: Int) {
companion object : Factory<Order> {
override fun create(): Order = Order(0)
}
}
🔹 4. Java의 static과 Kotlin의 차이점
항목 | Java static | Kotlin companion object |
정의 방식 | static 키워드 | companion object 키워드 |
사용 방법 | ClassName.method() | 동일 (ClassName.method()) |
내부 구조 | 정적 멤버 (JVM level) | 런타임 객체로 생성 (Companion) |
상속/인터페이스 | 불가 | 구현 가능 |
외부에서 접근 | 언제나 ClassName.staticMember | @JvmStatic 붙이면 Java에서도 동일하게 사용 가능 |
✅ Java 호환을 위해 사용하는 @JvmStatic
class Example {
companion object {
@JvmStatic
fun staticMethod() { println("호출됨") }
}
}
- Kotlin에서는 Example.staticMethod()
- Java에서도 Example.staticMethod()로 호출 가능
🔹 5. 실무에서의 활용 예시
✅ 정적 팩토리 메서드
class Member(val id: Long, val name: String) {
companion object {
fun fromJson(json: String): Member {
// JSON 파싱 로직 생략
return Member(1L, "ParsedUser")
}
}
}
- Member.fromJson(...) 형태로 사용 가능
- 팩토리 패턴을 더 자연스럽게 Kotlin 스타일로 적용
✅ 인터페이스 기반 전략 객체 등록
interface Validator {
fun isValid(value: String): Boolean
}
object EmailValidator : Validator {
override fun isValid(value: String): Boolean = value.contains("@")
}
- 애플리케이션에서 Validator 구현체를 싱글턴으로 주입하거나 등록할 때 유용
🚀 결론
키워드 | 목적 | 주요 특징 |
object | 싱글턴 객체 선언 | 전역 설정, 전략 객체 등 |
companion object | 클래스 수준의 정적 멤버 정의 | Java static 대체, 객체로서의 성격 |
@JvmStatic | Java 호출 호환 | Java에서도 static처럼 보이게 함 |
Kotlin은 object와 companion object를 통해 Java보다 더 명시적이고 유연하게 정적/싱글턴 구조를 구성할 수 있도록 설계되어 있습니다.
🤔 추가로 생각해 볼 질문들
- companion object는 내부적으로 어떤 클래스 구조로 컴파일될까?
- Kotlin에서는 static 유틸리티 함수를 어디에 두는 것이 가장 적절할까?
- object와 Singleton 디자인 패턴의 차이는?
- 여러 개의 object 선언이 공존할 때 메모리 구조는 어떻게 되는가?
- Java 코드에서 Kotlin companion object를 호출할 때 주의할 점은?