Arrays.copyOf creates a new array, but an object-array copy retains references to the same element objects.
Java array copies: new slots can still point at old objects
Separate slot ownership from element ownership
Replacing a source array slot does not replace the corresponding copied slot. Mutating an object that both slots still reference is different: both arrays observe the object's new state. The fixture performs both changes so the two ownership boundaries are visible in the output.
The same shallow-copy issue appears when a record holds an array and when a LinkedList clone copies nodes but shares elements. Defensive record copies and LinkedList cloning cover those callers.
Choose a domain copy deliberately
If a caller must own a frozen snapshot of mutable shipments, create new immutable value objects or copy each mutable element under a defined constructor. A second array alone is insufficient. The exact copy depth depends on the object graph and alias policy; a generic recursive copy routine cannot infer which shared references are intentional.
Arrays.copyOf also pads a longer copy with null elements. Validate a requested length before allocating, and do not assume the extra slots contain usable records. Array bounds explains the index contract.
Working program
import java.util.Arrays;
public class ShipmentArrayOwnership {
static final class Shipment {
String state;
Shipment(String state) { this.state = state; }
}
public static void main(String[] args) {
Shipment sharedShipment = new Shipment("queued");
Shipment[] live = {sharedShipment};
Shipment[] snapshotSlots = Arrays.copyOf(live, live.length);
live[0] = new Shipment("manual-review");
System.out.println(snapshotSlots[0].state);
sharedShipment.state = "sent";
System.out.println(snapshotSlots[0].state);
System.out.println(live[0].state);
}
}Output
queued
sent
manual-reviewCost and ownership
Copying n references takes O(n) time and O(n) additional slots. It does not allocate n new Shipment objects. A deeper copy has extra allocation and must state how nested references, cycles, and shared identities are handled.
Common Mistakes
- Do not call an object-array copy an immutable snapshot of its elements.
- Do not assume a longer copy has initialized domain values in padded slots.
- Do not expose a caller-owned array from a supposedly immutable object.
Read next
Java arrays and bounds, Java records with arrays: copy on input and output, Java LinkedList clone: copied nodes, shared element objects, Java pass-by-value: references and mutation.
