我们先来看几个小问题
我有一个自己写的类:
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
觉得写的不错的话,欢迎点赞评论收藏