You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中ArrayList的set方法未替换元素及Bullet移植对象引用问题

排查Kotlin移植Bullet引擎时ArrayList Set方法不生效的问题

我之前在把C物理引擎移植到Kotlin时也踩过类似的集合操作坑,尤其是从C的数组/容器思维转过来的时候,很容易因为Kotlin集合的特性踩雷。针对你遇到的问题,咱们一步步拆解分析:

首先聚焦stkStack[0] = element不生效的核心原因

1. 自定义resize函数的逻辑大概率是问题根源

Kotlin标准库的ArrayList并没有自带resize方法,所以你肯定是自己实现了扩展函数或者工具方法。这里最常见的坑是:

  • 如果你的resize是重新创建了一个新的ArrayList实例并赋值给stkStack,比如下面这种错误实现:

    var stkStack = ArrayList<StkNN>()
    fun resize(newSize: Int) {
        val newList = ArrayList<StkNN>(newSize)
        newList.addAll(stkStack)
        // 这里直接替换了stkStack的引用!
        stkStack = newList
    }
    

    那你之前执行的stkStack[0] = element是修改了旧的ArrayList实例,而resize之后stkStack指向了新的实例,旧实例的修改自然就看不到了。

  • 正确的resize应该是直接修改当前ArrayList的大小,而不是替换引用,比如:

    fun <T> ArrayList<T>.resize(newSize: Int, defaultValue: T) {
        while (size < newSize) {
            add(defaultValue)
        }
        while (size > newSize) {
            removeLast()
        }
    }
    

    这种实现会直接在原集合上调整大小,之前的set操作会被保留。

2. 验证索引有效性的小细节

虽然你判断了stkStack.isNotEmpty()才执行set,但调试时可以加个断言确认索引合法:

if (stkStack.isNotEmpty()) {
    check(stkStack.size > 0) { "stkStack size is 0 after isNotEmpty check" }
    stkStack[0] = element
} else {
    stkStack += element
}

极端情况下(比如多线程修改,但你这是调试HelloWorld应该是单线程),可能出现判断和set之间集合大小变化的情况,加断言能快速定位。

再说说你提到的对象引用相关问题

代码里的pa === pb是判断两个对象的引用是否完全相同,在移植C++的Bullet引擎时,这里容易踩的坑是:

  • 如果你的DbvtNode是通过JNI从C层映射过来的,要确保同一个C指针对应的Kotlin对象是单例的。比如用一个HashMap<Long, DbvtNode>来存储指针地址和Kotlin对象的映射,每次从C拿到指针时,先查映射表,存在就复用,不存在再创建新对象。否则会出现“逻辑上是同一个C节点,但Kotlin里是两个不同对象”的情况,导致===判断不符合预期。

调试建议

  1. 在stkStack[0] = element之后,立即打印stkStack[0]的内容和stkStack的identity hash(System.identityHashCode(stkStack));
  2. 执行resize之后,再打印一次这两个值,对比是否一致;
  3. 如果identity hash变了,说明resize替换了集合引用,这就是问题所在。

内容的提问来源于stack exchange,提问作者elect

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:15:31