Keywords: Java array copying | deep copy vs shallow copy | multidimensional array handling
Abstract: This article thoroughly examines the core issues of copying two-dimensional arrays in Java, analyzing common pitfalls of shallow copying and explaining the fundamental differences between reference assignment and content duplication. It systematically presents three methods for deep copying: traditional nested loops, System.arraycopy optimization, and Java 8 Stream API, with extended discussions on multidimensional and object arrays, offering comprehensive technical solutions.
Introduction
In Java programming, array copying is a common but error-prone operation, especially for multidimensional arrays. Many developers mistakenly believe that simple assignment operations can copy arrays, when in fact this causes two variables to reference the same memory address, leading to unintended data sharing. This article analyzes a typical scenario: a developer needs to regularly back up a frequently updated 2D array but finds that simple assignment methods like old = current and current = old fail to achieve the expected results.
Problem Analysis: The Pitfall of Reference Assignment
When executing old = current, the old variable is actually made to point to the same array object referenced by current. This is called "shallow copy" or "reference copy," not creating a new independent array. Consequently, any subsequent modifications to the current array will directly affect old, as both operate on the same memory region. Similarly, current = old in the keepold method merely switches the reference back without restoring the original data.
The root cause of this behavior is that arrays in Java are objects, and variables store references (memory addresses) rather than actual data. To truly copy array contents, one must create a new array object and copy each element value individually, i.e., implement a "deep copy."
Basic Solution: Nested Loop Copying
The most straightforward method is to use nested loops to traverse each dimension of the array:
public void copyArray(int[][] source, int[][] destination) {
for (int i = 0; i < source.length; i++) {
for (int j = 0; j < source[i].length; j++) {
destination[i][j] = source[i][j];
}
}
}This approach is clear and understandable, suitable for all two-dimensional primitive type arrays. However, note that the destination array must be initialized beforehand, and its dimensions must match the source array. For irregular arrays (rows of varying lengths), use source[i].length instead of a fixed length.
Performance Optimization: System.arraycopy Method
For large arrays, System.arraycopy can be used for optimization, as it employs native memory operations at a lower level, often faster than manual loops:
public static int[][] cloneArray(int[][] src) {
int length = src.length;
int[][] target = new int[length][];
for (int i = 0; i < length; i++) {
target[i] = new int[src[i].length];
System.arraycopy(src[i], 0, target[i], 0, src[i].length);
}
return target;
}This method copies each one-dimensional sub-array row by row, maintaining performance advantages while handling irregular arrays. Note that a new array must be created separately for each row.
Modern Approach: Java 8 Stream API
Since Java 8, the Stream API can be used for more concise copying:
int[][] copy = Arrays.stream(matrix)
.map(int[]::clone)
.toArray(int[][]::new);Here, int[]::clone invokes the clone method on each row array (the clone method of arrays implements deep copy), then collects them into a new two-dimensional array. This method offers concise code but note that clone only applies to primitive type arrays or immutable object arrays.
Extended Discussion: Multidimensional and Object Arrays
For arrays beyond two dimensions or object arrays, the problem becomes more complex. Copying object arrays requires distinguishing between shallow and deep copy:
- Shallow copy: Only copies object references, not the referenced objects themselves
- Deep copy: Recursively copies all nested objects
Implementing generic n-dimensional array copying requires recursively checking if each element is an array type. An alternative is to design a specialized NDimensionalArray class using flat storage and dimension multipliers for index calculation, simplifying copy operations to duplication of the underlying one-dimensional array.
Practical Recommendations and Considerations
1. Clarify requirements: Determine whether shallow or deep copy is needed
2. Performance considerations: For large arrays, prioritize System.arraycopy or Stream API
3. Boundary checks: Ensure the destination array has sufficient capacity; handle irregular arrays
4. Object arrays: If array elements are mutable objects, implement complete deep copy logic
5. Utility methods: Encapsulate common copy logic into reusable utility classes
Conclusion
The key to array copying in Java lies in understanding the difference between reference semantics and value semantics. Simple assignment operations only copy references; to create independent data copies, each element must be explicitly duplicated. Choose the appropriate method based on the specific scenario: traditional loops for clarity, System.arraycopy for performance advantages, and Stream API for modern syntactic sugar. For complex scenarios like object arrays or multidimensional arrays, more nuanced design considerations are required.