面试题答案
一键面试对象的创建、引用和销毁过程
- 创建:在Kotlin中,使用
new
关键字不是必须的。例如创建一个简单类Person
:
class Person(val name: String, val age: Int)
val person = Person("John", 30)
当执行上述代码时,JVM(Java虚拟机,Kotlin运行在JVM上)会在堆内存中为Person
对象分配空间,并根据构造函数初始化对象的属性。
- 引用:创建对象后,通过变量
person
来引用该对象。只要有活动的引用指向对象,对象就不会被销毁。多个变量可以指向同一个对象,例如:
val person1 = Person("Jane", 25)
val person2 = person1
这里person1
和person2
都指向堆内存中同一个Person
对象。
- 销毁:当对象不再有任何活动引用时,它就成为垃圾回收(GC)的候选对象。GC会在合适的时机回收这些对象占用的内存。例如:
val person = Person("Bob", 40)
// 假设此处之后person不再被使用,没有任何引用指向它
// 垃圾回收器会在某个时刻回收该Person对象占用的内存
从内存管理角度避免内存泄漏
- 避免长生命周期对象持有短生命周期对象的引用:例如在Android开发中,Activity是短生命周期的,如果一个静态变量(长生命周期)持有Activity的引用,当Activity销毁时,由于静态变量的引用存在,Activity及其相关资源无法被垃圾回收,从而导致内存泄漏。
class MyClass {
companion object {
private var context: Context? = null // 错误示例,静态变量持有Context引用
fun setContext(ctx: Context) {
context = ctx
}
}
}
修正方法是使用弱引用:
class MyClass {
companion object {
private var weakContext: WeakReference<Context>? = null
fun setContext(ctx: Context) {
weakContext = WeakReference(ctx)
}
}
}
- 及时释放资源:在对象不再使用时,及时释放相关资源,例如关闭文件、数据库连接等。
复杂类继承和对象交互场景下的性能优化
- 对象复用:可以使用对象池模式。例如在游戏开发中,频繁创建和销毁子弹对象可能导致性能问题。可以创建一个子弹对象池:
class Bullet {
// 子弹相关属性和方法
}
class BulletPool {
private val pool = mutableListOf<Bullet>()
fun getBullet(): Bullet {
return if (pool.isNotEmpty()) {
pool.removeAt(0)
} else {
Bullet()
}
}
fun returnBullet(bullet: Bullet) {
pool.add(bullet)
}
}
- 减少不必要的对象创建:对于一些不变的对象,可以使用
companion object
或object
关键字创建单例。例如,一个配置类:
object AppConfig {
val apiBaseUrl = "https://example.com/api"
val appVersion = "1.0"
}
这样在整个应用中只存在一个AppConfig
实例,避免了重复创建。另外,在循环中尽量避免创建对象,如果可能,在循环外创建并复用。例如:
// 错误示例
for (i in 0 until 1000) {
val tempList = mutableListOf<Int>()
// 使用tempList
}
// 正确示例
val tempList = mutableListOf<Int>()
for (i in 0 until 1000) {
// 使用tempList
tempList.clear()
}