Search code examples
javagenericsconstructordefensive-copy

How to deal with various cases of defensive programming?


This is an example of defensive copy in Effective java. Assume that scenario's in my underlying questions need a defensive copy, and cannot do with a comment asking client to avoid mutating objects passed in.

public Period(Date start, Date end) {
    this.start = new Date(start.getTime());
    this.end = new Date(end.getTime());
}

Questions:

  1. What to do if Date did not have a constructor to take itself in, to make my self more general, an object is passed with no mechanism to replicate itself, and such object does not belong to us, ie we cant change it in any way ?

  2. What if the constructor took type parameter as an argument, say Period(T object) and T could be mutable so needs defensive copy. We dont have any idea of what is T. How to do defensive copy in this case ?

  3. What is an interface is passed where some of its subclasses do have a constructor like Date to create an object of itself and some of its subclasses dont have any mechanism to do so ?

  4. How deep should we defensively copy ? Lets say we copy an array, but array elements were mutable ?


Solution

    1. If all its state is available, you can extract its state and construct a new object by yourself. Otherwise, you can't do anything about it except using nasty reflection or serialization tricks.
    2. If T is not an instance of a class that allows copying itself, you can't do anything.
    3. You can't do anything about it.
    4. It depends.

    By reading your question, it looks like you would like to apply the "defensive copy" advice everywhere. You shouldn't. Most of the time, code using mutable objects want a reference to the original object, and not a copy. Especially if what you get as argument is an instance of an abstract class or interface.

    You're forced to make a defensive copy of Date because it's mutable value type that shouldn't be mutable, and wouldn't be if it had been properly designed. If you promote immutability for value types, then defensive copies become unnecessary. For non-value types, you generally don't want a copy, but a reference to the object.