阅读 356

关于将 Activity 放进 List 这件事

我们先来看几个小问题

我有一个自己写的类:

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里面的对象,这很好理解,因为赋值操作并不是在原对象的基础上改动,而是将声明的对象名指向了另一个对象(不考虑基本数据类型)

如图所示:(方块代表内存,虚线代表空)

未sd绘图.png

思考:这会引起什么问题

如果你了解过JVMGC原理。可能听说过一个叫可达性算法的,当对象不可达的时候,就会在下次GC的时候被回收

可达的意思就是对某块内存里的变量有引用,也就是我图片里黑色细线的箭头

简而言之:你如果有途径获取某个对象,那他就是可达的,反之就是不可达

当我们将对象放进List的时候,这个List就持有了这个对象的引用(这个List就会引出一个箭头,指向对象

如图所示:(方块代表内存,虚线代表空)

未命名绘图-第 2 页.png 可见,当person被赋值为nullPerson@5594a1b5这块内存依旧可达,我们依旧可以用List访问他,所以他不会被JVM回收

如果我们将Activity的实例化对象放进了List里,如果 操作不当 ,很可能会导致Activity所占内存空间无法释放,破坏生命周期

通用来讲,我们尽可能不要引用ActivityService等系统级别的组件,无论是List还是HashMap,还是其他引用的方式

OVER

觉得写的不错的话,欢迎点赞评论收藏

文章分类
Android
文章标签