我们先来看几个小问题
我有一个自己写的类:
class Person(var name: String) {
fun introduce(): String = "My name is $name"
}
复制代码
问题1:将一个实例化的对象放进List里,这个过程是会重新创建一个对象,还是直接开辟一块内存空间,指向这个实例化的对象?
简言之:
我将Person
放进List
里面,在外面改名字,List
里面也会改吗?
答案:
会!!
fun main(args: Array<String>) {
val list = arrayListOf<Person>()
val person = Person("吴彦祖")
list.add(person)
println(person.toString())
println(list[0].toString())
println(person.name)
println(list[0].name)
person.name = "彭于晏"
println(person.name)
println(list[0].name)
list[0].name = "李易峰"
println(person.name)
println(list[0].name)
}
复制代码
输出结果:
Person@5594a1b5
Person@5594a1b5
吴彦祖
吴彦祖
彭于晏
彭于晏
李易峰
李易峰
复制代码
可以看到我们打印出的HashCode
是完全一致的,并且外面声明的对象是和List
里面的同步更改的!
这个是很合理的,无论是从内存模型
上理解,还是设计
上理解,都很合理,而且,这很符合现实生活
,现实中排队的时候,你也是自己去排队,并不是召唤一个影分身,让他代替你排队。
问题二:将放进List
的对象释放( 赋值为null
),List
里的对象会变吗?
fun main(args: Array<String>) {
val list = arrayListOf<Person?>()
var person: Person? = Person("吴彦祖")
list.add(person)
println(person.toString())
println(list[0].toString())
println(person?.name)
println(list[0]?.name)
person = null
println(person)
println(list[0])
}
复制代码
输出结果:
Person@5594a1b5
Person@5594a1b5
吴彦祖
吴彦祖
null
Person@5594a1b5
复制代码
可见,将外部对象释放并不会释放List
里面的对象,这很好理解,因为赋值操作
并不是在原对象的基础上改动,而是将声明的对象名指向了另一个对象(不考虑基本数据类型)
如图所示:(方块代表内存,虚线代表空)
思考:这会引起什么问题
如果你了解过JVM
的GC
原理。可能听说过一个叫可达性算法
的,当对象不可达的时候,就会在下次GC的时候被回收
可达
的意思就是对某块内存里的变量有引用
,也就是我图片里黑色细线的箭头
简而言之:你如果有途径获取某个对象,那他就是可达的,反之就是不可达
当我们将对象
放进List
的时候,这个List
就持有了这个对象
的引用(这个List
就会引出一个箭头,指向对象
)
如图所示:(方块代表内存,虚线代表空)
可见,当person
被赋值为null
,Person@5594a1b5
这块内存依旧可达
,我们依旧可以用List
访问他,所以他不会被JVM
回收
如果我们将Activity
的实例化对象放进了List
里,如果 操作不当 ,很可能会导致Activity
所占内存空间无法释放,破坏生命周期
通用来讲,我们尽可能不要引用Activity
,Service
等系统级别的组件,无论是List
还是HashMap
,还是其他引用的方式
OVER
觉得写的不错的话,欢迎点赞评论收藏
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END