코틀린에서 전역변수 사용
class Person {
String name;
}
public class Main {
static Person person;
public static void main(String[] args) {
person = new Person();
}
}
자바 개발자라면 클래스 내 변수를 어느 메소드에서 자유롭게 접근하도록 하기 위해
전역변수로 선언만 해둔 후, 이를 특정 시점에 초기화 및 생성시켜 써본 경험이 한 번쯤은 있으실 겁니다.
class Person
val person:Person // 초기화하지 않으면 에러 발생!!
fun main() {
val person = Person()
}
하지만 코틀린에서는 위와 같은 코드는 성립이 안됩니다.
코틀린에서는 변수의 선언과 동시에 초기화하도록 권장하기 때문입니다.
class Person
var person:Person? = null // null로 초기화 하여 에러는 나지 않지만, 권장하진 않음
fun main() {
val person = Person()
}
물론, ? 키워드를 붙여 nullable 타입으로 만든 뒤, null로 초기화하여 사용할 수 있으나,
null로 초기화하는 것은 코틀린에서 그닥 권장하는 사용법은 아닙니다.
lateinit을 사용한 늦은 초기화
class Person
lateinit var person: Person // lateinit을 붙여 늦게 초기화해준다고 명시
lateinit val person2: Person // 에러발생 !! val에는 사용 불가능
fun main() {
val person = Person()
}
이럴때 사용할 수 있는게 lateinit 키워드입니다.
키워드 이름에서 알 수 있듯, 늦게 초기화해준다는 의미입니다.
이는 val에는 사용 불가하며 오직 var에만 사용 가능합니다.
또한, Int, Long, Double, Char와 같은 primmitive 타입에는 사용이 불가합니다.
뭐... int 같은 경우는 어차피 자바에서도 별 값을 주지 않으면 0으로 초기화되니,
var n = 0 과 같이 그냥 초기화하는게 좋을 것 같네요.
초기화 했는지는 어떻게 확인해?
class Person
lateinit var person: Person // lateinit을 붙여 늦게 초기화해준다고 명시
fun main() {
if (::person.isInitialized) { // 초기화가 되었는지 확인
println("Initialized")
} else {
println("Not initialized")
}
}
// 출력
>> Not initialized
초기화 여부는 ::(객체).isInitialized 를 통해 확인할 수 있습니다.
앞에 꼭 ::를 붙여야 확인할 수 있습니다.
초기화 지연 - lazy
class Person {
init { println("Person created") }
fun sayHello() { println("Hello") }
}
val person by lazy { Person() } // 초기화를 지연시킴
fun main() {
println("Point1")
person.sayHello() // 처음 사용되는 시점에 초기화
println("Point2")
}
// 출력
>> Point1
Person created
Hello
Point2
lazy는 지연 초기화를 사용할 때 쓰는 키워드로, 오직 val만 가능합니다.
이는 말 그대로 초기화를 지연시키는 역할을 하는데요.
by lazy { }와 같이, 람다식을 이용해 사용합니다.
위 예시 코드에서, Person 클래스는 생성되는 순간 init에서 println(”Person created”)를 출력합니다.
그리고, 전역변수로써, person을 선언했고, lazy의 바디부분에 생성 코드를 삽입했습니다.
이후, main()에서 person 객체를 처음 사용하는 순간 lazy 바디 내 코드가 실행됩니다.
class Person {
init {
println("Person created")
}
fun sayHello() {
println("Hello")
}
}
val person by lazy {
// lazy 바디 내 코드가 실행됨.
val a = 10
val b = 100
println(a + b)
println("코드 실행")
Person() // 제일 마지막 줄이 person에 대입
}
fun main() {
println("Point1")
person.sayHello() // 처음 사용되는 시점에 초기화
println("Point2")
}
>>> Point1
110
코드 실행
Person created
Hello
Point2
참고로, lazy의 바디 부분은 람다식으로써,
person.sayHell()를 통해 person 객체가 처음 호출되는 순간,
lazy의 바디 내 코드가 순차적으로 실행되며,
제일 마지막줄만 person에 대입됩니다.
lazy 키워드를 잘 활용하면 메모리와 시간 측면에서 더 효율적으로 작동할 수 있습니다.
부록. lazy를 유용하게 써본 개인적 경험
사실 저는 lazy 키워드를 메모리 측면보다는, 프로그램 흐름을 맞추는데 유용하게 썼는데요.
private val chatAdapter = ChatAdapter(applicationContext, chatModels)
// 엥 applicationContext 없는데요. 앱 팅김!!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.rvChat = chatAdapter
}
리사이클러뷰 등을 사용할 땐, 저는 주로 Adapter를 전역변수로 두는 편입니다.
Adapter에 굳이 context를 건네줄 필요는 없지만,
어댑터에서 특정 작업을 할 때 context가 필요한 경우가 있어 종종 넘겨주곤 합니다.
하지만 applicationContext는 onCreate()가 호출될때 생성되며,
전역변수로 선언+초기화를 할 경우,
onCreate()보다 먼저 생성되어 context를 가져오지 못해 앱이 팅기곤 했습니다.
private lateinit chatAdapter:ChatAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
// 전역변수로 선언만 해두고, 생성은 onCreate() 이후에 해야함.
chatAdapter = ChatAdapter(applicationContext, chatModels)
binding.rvChat = chatAdapter
}
따라서, 해당 예제에서 context를 넘겨주고 싶을 땐, 전역변수로 선언만 해두고,
onCreate() 이후 생성하는 코드를 따로 넣어줘야 했습니다.
private val chatAdapter by lazy { ChatAdapter(applicationContext, chatModels) }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.rvChat = chatAdapter
}
하지만 lazy 키워드를 사용하여, 선언과 초기화를 동시에 처리할 수 있었습니다.
(실제로 초기화가 된 것은 아닙니다)
안드로이드에서 거의 모든 코드는 onCreate() 이후 작동합니다.
따라서, lazy를 사용하면 자연스럽게 context를 onCreate() 이후에 넘겨줄 수 있게 되었습니다.
다시 한 번 말씀드리지만… 리사이클러뷰 어댑터에 굳이 context를 넘겨줄 필요는 없습니다.
액티비티보단 리사이클러뷰에서 처리하는게 더 나을 것 같은 작업이 있어 context를 넘겨줬을 뿐…
'코틀린 파헤치기 > 2부. 코틀린 객체지향' 카테고리의 다른 글
[코틀린 2부] 8. 코틀린과 상수 Const (0) | 2023.03.15 |
---|---|
[코파기 2부] 7. 코틀린과 열거형 클래스 Enum (1) | 2023.03.15 |
[코파기 2부] 5. 코틀린과 추상 클래스와 인터페이스 (+ 둘의 차이점) (3) | 2023.03.15 |
[코파기 2부] 4. 코틀린과 접근 제한자 (0) | 2023.03.15 |
[코파기 2부] 3. 코틀린과 상속(Inheritance)와 오버라이딩(Override) (0) | 2023.03.15 |