行优先遍历更快,因java二维数组是“数组的数组”,每个一维子数组内部连续存储,arri与arri相邻而arri与arri+1分散,符合cpu缓存局部性原理。

Java多维数组遍历性能差异,核心不在语法本身,而在内存布局与CPU缓存如何协同工作。行优先遍历通常明显更快——这不是经验法则,而是由Java二维数组底层存储方式决定的硬性事实。
Java二维数组实际是“数组的数组”
Java没有真正意义上的连续二维数组。声明 int[][] arr = new int[1000][1000] 时,外层数组(长度1000)存放的是1000个引用,每个引用指向一个独立的一维数组对象。这些一维数组在堆内存中分散分布,彼此不连续。
但关键点在于:每个一维子数组内部元素是连续存储的。也就是说,arr[i] 是一块连续内存,而 arr[i][j] 和 arr[i][j+1] 紧挨着;但 arr[i][j] 和 arr[i+1][j] 往往相隔很远。这直接决定了访问模式的效率边界。
行优先遍历符合局部性原理
当你写:
- for (int i = 0; i
- for (int j = 0; j
- doSomething(arr[i][j]);
内层循环每次访问的是同一块连续内存(arr[i] 的元素),CPU缓存能一次加载多个相邻元素(如64字节缓存行可覆盖16个int),后续读取大概率命中缓存。
实测中,对10240×10240的byte数组求和,行优先耗时383ms,列优先达1453ms——慢近4倍。即使数组更小(如5000×5000),差距也常达7倍以上(31ms vs 234ms)。
列优先遍历触发大量缓存未命中
列优先写法:
- for (int j = 0; j
- for (int i = 0; i
- doSomething(arr[i][j]);
每次 arr[i][j] 都要跳转到不同一维数组的第j个位置。这些地址彼此分散,几乎每次访问都跨缓存行,迫使CPU反复从主内存加载新数据,缓存利用率极低。
尤其当数组规模增大、JVM堆内存碎片增多时,这种跳跃更明显,性能衰减加剧。
高维数组同样适用该规律
三维数组 int[][][] data 中,最内层循环应遍历最右下标(如k),中间层遍历j,最外层遍历i:
for (int i = 0; i
for (int j = 0; j
for (int k = 0; k
这样保证每次内层迭代都在同一块连续内存上操作。
若颠倒顺序(如先k后i),就等于人为打乱访问局部性,性能损失会随维度升高而放大。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











