[코틀린기초] 29. 정적 변수와 컴페니언 객체
정적이란 메모리에 딱 생성되어 고정되어있는 것.
보통 클래스는 동적으로 객체를 생성하는데 정적으로 고정하는 방법은?
- 자바에서는 static 변수 또는 객체
- 코틀린에서는 이를 **컴페니언** 객체로 사용
- 프로그램 실행 시 고정적으로 가지는 메모리로 객체 생성 없이 사용한다.
-
단, 자주 사용되지 않는 변수나 객체를 만들면 메모리 낭비다!!!!
#### 컴패니언 객체는 실제 객체의 싱글톤으로 정의됨 -> 객체를 여러개 생성해도 컴페니언 객체는 단 하나!
class Person{
var id: Int = 0
var name: String = "Youngdeok"
companion object{ // 고정된 static 내부 클래스처럼 정의 된다.
var language: String = "Korean"
fun work(){
println("working...")
}
}
}
fun main(){
println(Person.language) // 인스턴스 생성 없이 기본 값 사용
Person.language = "English" // 기본 값 접근 가능
println(Person.language) // 변경된 내용 출력
Person.work() // 메서드 실행
//println(Person.name) // name은 컴페니언 객체가 아니므로 에러!
}
## 자바에서 코틀린 컴패니언 객체 사용하기
- 자바에서는 코틀린의 컴페니언 객체를 접근하기 위해 @JvmStatic 애너테이션을 사용한다.
//KCustomer.kt
class KCustomer{
companion object{
const val LEVEL ="INTERMEDIATE" // const 와 val을 함께 사용하면, 컴파일 시간에 값이 결정됨
@JvmStatic fun login() = println("Login...") // 애너테이션 사용
}
}
// KCustomerAccess.java
public class KCostomerAccess{
public static void main(String[] args){
System.out.println(KCustomer.LEVEL)
KCustomer.login(); // 애너테이션을 사용할 때 접근 법
KCustomer.Companion.login(); // 위와 동일한 결과로 애너테이션을 사용하지 않을 때 접근법
}
}
## 최상위 함수 정리
- 클래스 없이 만들었던 최상위 함수들은 객체 생성 없이도 어디서든 실행
- 패키지 레벨 함수라고도 함
-
최상위 함수는 결국 자바에서 static final로 선언된 함수임!!!
### 자바에서 코틀린의 최상위 함수 접근
-
코틀린의 최상위 함수는 클래스가 없으나 자바와 연동시 내부적으로 파일명에 Kt 접미사가 붙은 클래스를 자동 생성하게 된다.
-
자동 변환되는 클래스 명을 명시적으로 지정하고자 하는 경우 @file:JvmName(“ClassName”)을 코드 상단에 명시한다.
//PackageLevelFuncion.kt
@file:JvmName("PKLevel") // 변환되는 클래스 명을 명시적으로 지정
fun packageLevelFunc(){
println("Package-Level Function")
}
fun main(){
packageLevelFunc()
}
// PackageLevelAccess.java
public class PackageLevelAccess{
public static void main(String[] args){
PKLevel.packageLevelFunc(); // 명시적으로 지정한 클래스 명 사용
}
}
## object와 싱글톤
-
상속할 수 없는 클래스에서 내용이 변경된 객체를 생성할 때
- 자바에서는 익명 내부 클래스로 새로운 클래스를 선언
- 코틀린에서는 object 표현식이나 object 선언으로 이 경우를 더 쉽게 처리한다.
- 주/부 생성자를 사용할 수 없다.
- 단, 처음부터 메모리에 고정되는 것이 아닌 최초 접근시 객체가 생성되어 고정된다.
object OCustomer{
var name = "Kildong"
fun greeting() = println("Hello world!")
val HOBBY = Hobby("Basketball")
init{
println("Init!")
}
}
class Hobby(val name: String)
fun main(){
OCustomer.greeting() // 객체의 접근 시점
OCustomer.name = "Dooly"
println("name = ${OCustomer.name}")
println(OCustomer.HOBBY.name)
}
### object 표현식
- object 선언과 달리 이름이 없고 싱글턴이 아님
- 표현식이 사용될 때마다 새로운 인스턴스가 생성
- 이름이 없는 익명 내부 클래스로 불리는 형태를 object 표현식으로 만들 수 있다.
-
하위 클래스를 만들지 않고도 새로운 구현을 만들수 있다!
open class Superman(){
fun work() = println("Taking photos")
fun talk() = println("Talking with people")
open fun fly() = println("Fly")
}
fun main(){
val pretendedMan = object: Superman(){ // object 표현식으로 fly() 구현 재정의
override fun fly() = println("I'm nor a real superman")
}
pretendedMan.work()
pretendedMan.talk()
pretendedMan.fly()
}