I was reading some Java recently and came across something (an idiom?) new to me: in the program, classes with multiple constructors would also always include a blank constr
Is the object Serializable?
To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype's public, protected, and (if accessible) package fields. The subtype may assume this responsibility only if the class it extends has an accessible no-arg constructor to initialize the class's state. It is an error to declare a class Serializable if this is not the case. The error will be detected at runtime.
During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class. A no-arg constructor must be accessible to the subclass that is serializable. The fields of serializable subclasses will be restored from the stream
For some POJO classes or simple class, default constructor is useful when you sometimes want to do unit testing on the class using them. You don't need to mock them, you can new an object with default constructor and test the value set and get from them or pass them as an argument.
I usually write one constructor that fully initializes the object; if there are others, they all call this(...) with appropriate defaults.
An object should be 100% initialized and ready for use when it's created.
Some frameworks, for example Hibernate, demand a no-arg constructor. The way they clash with best practices makes me uneasy sometimes.
I am not sure that the code you were reading was high quality (I've reviewed some bioinformatics code in the past and it is unfortunately often not written by professional developers). For example, that third constructor is not a copy constructor and generally there are problems in this code, so I wouldn't "read too much into it".
The first constructor is a default constructor. It only initializes the bare minimum and lets users set the rest with getters and setters. Other constructors are often "convenience constructors" that help create objects with less calls. However, this can often lead to inconsistencies between constructors. In fact, there is recent research that shows that a default constructor with subsequent calls to setters is preferable.
There are also certain cases where a default constructor is critical. For example, certain frameworks like digester (used to create objects directly from XML) use default constructors. JavaBeans in general use default constructors, etc.
Also, some classes inherit from other classes. you may see a default constructor when the initialization of the parent object is "good enough".
In this specific case, if that constructor was not defined, one would have to know all the details in advance. That is not always preferable.
And finally, some IDEs automatically generate a default constructor, it is possible that whoever wrote the class was afraid to eliminate it.
Yes, I agree the "blank" constructor should not always exist (in my experience beginners often make this mistake), although there are cases when blank constructor would suffice. However if the blank constructor violates the invariant that all the members are properly instantiated after construction, blank constructor should not be used. If the constructor is complicated, it is better to divide the construction into several protected/private methods. Then use a static method or another Factory class to call the protected methods for construction, as needed.
What I wrote above is the ideal scenario. However, frameworks like spring remove the constructor logic out of the code and into some xml configuration files. You may have getter and setter functions, but probably may be avoided from the interface, as described here.
Having a default and empty (blank) constructor prevents you from having any final fields. This leads to a lot of mutability where there it is often not needed.
The builder pattern allows you to mix these two styles and allow more flexible initialization while still having immutability by hiding a many-arg constructor behind the factory.