반응형
불변 객체란
객체를 생성한 이후 변하지 않는 객체를 말한다.
private, val과 같이 데이터가 변하지 않기 때문에 생성된 객체를 신뢰할 수 있게 된다.
얕은 복사란
해당 객체의 메모리 주소 값만 복사하는 것을 말한다.
주소만 복사하기 때문에 기존 객체가 변하게 되면 영향을 받게 된다.
깊은 복사란
해당객체의 데이터를 복사하는 것을 말한다.
데이터를 복사하기 때문에 기존 객체의 변경에도 영향을 받지 않는다.
코틀린에서는 객체의 .copy()등을 이용한다.
방어적 복사란
생성자를 통하여 초기화할 때 새로운 객체 등으로 감싸서 복사하는 방법이다.
코틀린의 toList(), toMutableList()로 사용할 수 있다.
public fun <T> Collection<T>.toMutableList(): MutableList<T> {
return ArrayList(this)
}
public fun <T> Iterable<T>.toList(): List<T> {
if (this is Collection) {
return when (size) {
0 -> emptyList()
1 -> listOf(if (this is List) get(0) else iterator().next())
else -> this.toMutableList()
}
}
return this.toMutableList().optimizeReadOnlyList()
}
fun main() {
val users = ArrayList<User>()
users.add(User("lee", 33))
users.add(User("kim", 34))
users.add(User("park", 35))
val cloneUsers = users.toMutableList()
cloneUsers.add(User("na", 36))
println(users.toString())
println(cloneUsers.toString())
}
data class User(val name: String, var age: Int)
출력
[User(name=lee, age=33), User(name=kim, age=34), User(name=park, age=35)]
[User(name=lee, age=33), User(name=kim, age=34), User(name=park, age=35), User(name=na, age=36)]
하지만 방어적 복사는 깊은 복사가 아니라 User객체의 주소값을 공유하고 있기 때문에 아래와 같이 lee의 나이가 변경 되었을 때
users와 cloneUsers의 lee의 나이가 변경되는 것을 확인할 수 있다.
fun main() {
val users = ArrayList<User>()
users.add(User("lee", 33))
users.add(User("kim", 34))
users.add(User("park", 35))
val cloneUsers = users.toMutableList()
cloneUsers.add(User("na", 36))
cloneUsers\[0\].age = 35
println(users.toString())
println(cloneUsers.toString())
}
data class User(val name: String, var age: Int)
출력
[User(name=lee, age=35), User(name=kim, age=34), User(name=park, age=35)]
[User(name=lee, age=35), User(name=kim, age=34), User(name=park, age=35), User(name=na, age=36)]
위와 같은 문제를 막기 위해서는 User를 깊은 복사 해주어야 한다.
fun main() {
val users = ArrayList<User>()
users.add(User("lee", 33))
users.add(User("kim", 34))
users.add(User("park", 35))
val cloneUsers = ArrayList(users.map { it.copy() })
cloneUsers.add(User("na", 36))
cloneUsers\[0\].age = 35
println(users.toString())
println(cloneUsers.toString())
}
data class User(val name: String, var age: Int)
출력
[User(name=lee, age=33), User(name=kim, age=34), User(name=park, age=35)]
[User(name=lee, age=35), User(name=kim, age=34), User(name=park, age=35), User(name=na, age=36)]
불변 객체의 장점
- 병렬 프로그래밍에서 동기화 관련 문제를 해결할 수 있다.
- 데이터가 바뀜으로 발생하는 부수효과를 방지할 수 있다.
반응형
'코틀린' 카테고리의 다른 글
Sealed Class와 Enum Class의 차이점 (0) | 2025.01.15 |
---|---|
코틀린 제네릭이란? (in, out) (1) | 2025.01.14 |
inline 함수 (0) | 2022.08.31 |
코틀린 by란? (0) | 2022.06.28 |
코틀린 플로우 (0) | 2022.06.01 |