See the new features list.
Month: March 2008
Shallow Clone
A typical way of cloning an object is to use super.clone() to shallow-clone it, then modifying/cloning any members to create a complete clone.
Extra care must be taken if the original contains members that reference back to itself, e.g.
public class Model implements Cloneable {
private PropertyChangeSupport support;
private String name;
public Model(String name) {
support= new PropertyChangeSupport(this);
this.name = name;
}
public void setName(String newName) {
String oldName = this.name;
this.name = newName;
support.firePropertyChange("name", oldName, this.name);
}
}
When this object is cloned the support member variable still references the original object (due to Object’s direct member assignment), thus the listeners would receive a wrong reference.
To fix this, implement a custom clone() method to take care of it. Make sure a new instance is created for it. If you simply change the reference inside the PropertyChangeSupport object, it will screw up the original object instead.
public Object clone() {
Model clonedModel = (Model)super.clone();
clonedModel.support = new PropertyChangeSupport(clonedModel);
return clonedModel;
}
An Array of a List of Strings
I needed to create an Array of a List of Strings (actual problem anonymized). With generics I declared the variable:
List[] typedListArray;
Then I proceeded to create it.
typedListArray = new List[4]; // compile error
I needed to create the array first, like how I create new int[4];. But no matter how I moved the syntax, it wouldn’t compile. Read the JLS and searched the web, and finally found this explanation. It was not even a solution.
The reason the creation was disallowed was due to type erasure. Java’s implementation of generics only applies at compile time to ensure that the correct types are used. During runtime, the type information is erased. By creating a concrete parameterized array type, the runtime is unable to ensure that the correct items are added to the list. It is therefore senseless to allow the creation. The ways “around” it were to live with the warning, or to suppress it with annotations.
Then why allow the declaration?
Constructor Design
2 colleagues were in a “heated” argument over a design of constructors, which needed to have some form of the following parameters:
- int code, String name, Serializable objParam
- int code, String name, String xmlParam
The 3rd param could be either a String representing XML for an object, or a Serializable object. Both of them agreed there would be trouble differentiating between the two parameters, since Strings are serializable as well, and sometimes clients may want a String to be the Serializable param instead of XML.
To me it’s a non-issue, since the compiler is smart enough to use the String constructor if 3rd parameter was a String, and use the Serializable if I explicitly cast the String into Serializable (if I remember my signature-matching facts correctly).
One of them strongly pushed for a single constructor with 4 parameters, and passing in null for either the 3rd or 4th one. He argued this resolves ambiguity, as well as too many combinations of constructors available.
The other wishes to remove the optional 3rd parameter and use only 2 parameters. The 3rd parameter would be achieved using set methods.
Debate ensued, each bringing up points to support their views, such as cleanliness of API, ease of use, danger of forgetting to set the parameters, more parameters added next time. I wasn’t actually in the debate, I just happened to be the 3rd party in their chat window.
After a long while I suggested using static creational methods to differentiate between the 2 constructors. Something like Class.createXXXType() and Class.createYYYType() which I felt would be clear which “constructor” to refer to, non-ambiguity as well as stability of the instance created.
They didn’t take it very well too, and I left my suggestion as it is. There’s still no conclusion yet, they are still hesitating to call for a design review for this small matter.