In Java, a defensive copy is a programming technique used to protect the internal state of an object from being unintentionally modified by external code. This is particularly important when dealing with mutable objects, such as Date objects, arrays, or collections, that are passed into or returned from a class.β
Why Defensive Copies are Necessary:
When you pass a mutable object into a constructor or method, or return a mutable object from a getter, you are essentially sharing a reference to that object. If the external code that holds this reference modifies the object, it will directly affect the internal state of your class, potentially leading to unexpected behavior, bugs, or security vulnerabilities.
How to Implement Defensive Copies:
Defensive copies are typically implemented in two key scenarios:
public class MyClass {
private Date myDate;
public MyClass(Date date) {
// Defensive copy in constructor
this.myDate = new Date(date.getTime());
}
public void setMyDate(Date date) {
// Defensive copy in setter
this.myDate = new Date(date.getTime());
}
}
- In Constructors and Setters: When receiving a mutable object as a parameter, create a new instance of that object and copy the contents of the received object into the new instance. This ensures that the internal state of your class is independent of the external object.
public class MyClass {
private Date myDate;
// ... constructor and other methods ...
public Date getMyDate() {
// Defensive copy in getter
return new Date(myDate.getTime());
}
}
Important Considerations:
- In Getters: When returning a mutable object from a getter method, return a new instance of that object containing a copy of the internal state. This prevents external code from modifying the internal object directly.βIn
- Mutable vs. Immutable Objects:Defensive copies are only necessary for mutable objects. Immutable objects (like
StringorInteger) cannot be changed after creation, so defensive copies are not needed for them. - Deep vs. Shallow Copies:Depending on the complexity of your objects, you might need to perform a deep copy (copying nested mutable objects) rather than a shallow copy (copying only the top-level object).
- Performance:Creating defensive copies can introduce some performance overhead, so it's important to weigh the benefits of protection against the potential performance impact, especially in performance-critical applications.
- Alternatives:In some cases, making objects immutable or using immutable collections (like
Collections.unmodifiableList()) can be more effective and simpler alternatives to defensive copying.
Resources:
- https://medium.com/@harshavardhan.katkam/java-defensive-copying-how-to-truly-protect-your-class-1355b0fac11b
- https://medium.com/@vino7tech/ensuring-immutability-in-java-defensive-copying-of-lists-8dc61cfb5a07
- https://medium.com/@harshavardhan.katkam/immutable-objects-in-java-when-and-how-to-design-them-0f7209610e83