Use of Private Constructor in Java
A private constructor is used when you have a class that you don’t want to be instantiated by another class.
The most common cases where a private constructor is used are:
- classes providing only static elements (methods or constants)
- In case of a singleton design pattern
Classes containing only static methods and constants
In these cases, Object construction is entirely forbidden, either by the caller or by the native class, because there is no situation where an object of this class is needed.
Why not simply don’t declare a constructor? Because in that case, the class will have the default constructor, and therefore the creation of an instance will be possible.
What about the native class? It can call its private constructor and create an object.
To prevent that, we can add throw new AssertionError(); in the constructor.
public class ConstantsClass { … private ConstantsClass(){ //this prevents even the native class from //calling this ctor as well : throw new AssertionError(); } }
Constructor in a singleton design pattern
In these cases, Object construction is entirely forbidden for the caller but it is allowed internally.
Copy constructors
When you manipulate mutable objects (A mutable object is an object which can change its state after construction), you will probably need to find a way to make copies of these objects.
This can be done using Copy constructors: they are easily implemented and it’s better than using the clone method.
Note that there is no default copy constructor in Java, you have to implement your own.
copy constructors are simple to implement, as we can see in the following example:
public class Student { private String fullName; private String gender; private int age; private String placeOfBirth; public Student(String fullName, String gender, int age, String placeOfBirth) { super(); this.fullName = fullName; this.gender = gender; this.age = age; this.placeOfBirth = placeOfBirth; } /* * Copy Constructor * takes as argurment a Student object * extract the argument's data, and forward to the regular constructor */ public Student(Student student) { this(student.getFullName(), student.getGender(), student.getAge(), student.getPlaceOfBirth()); } public static void main(String[] args) { Student student1 = new Student("Student 1", "M", 15, "NY"); // let's create some copies, // then change data that differ from the first object Student student2 = new Student(student1); student2.setFullName("Student 2"); Student student3 = new Student(student1); student3.setFullName("Student 3"); student3.setGender("F"); // let's copy from student3 Student student4 = new Student(student3); student4.setFullName("Student 4"); Student student5 = new Student(student1); student5.setFullName("Student 5"); student5.setPlaceOfBirth("LA"); System.out.println(student1); System.out.println(student2); System.out.println(student3); System.out.println(student4); System.out.println(student5); } // getters and setters @Override public String toString(){ return getFullName() +": is a "+ getGender() +" , "+ getAge() +" years old, born in "+ getPlaceOfBirth(); } }
Result:
Student 1: is a M , 15 years old, born in NY Student 2: is a M , 15 years old, born in NY Student 3: is a F , 15 years old, born in NY Student 4: is a F , 15 years old, born in NY Student 5: is a M , 15 years old, born in LA
// Alternative style for a copy constructor, using a static newInstance method. public static Student newInstance(Student student) { return new Student(student.getFullName(), student.getGender(), student.getAge(), student.getPlaceOfBirth()); }
Note that following doesn’t involve a copy constructor call as
Student student2 = student1;;
non-primitive variables are just references. The previous line only means that the 2 objects have the same reference.
When to use “this” in a constructor
‘This’ keyword refers to the current instance of the class.
Inside a constructor, you can use the “this” keyword in different ways for example:
- Like we just saw in copy constructor, when calling another constructor;
public Student(Student student) { this(student.getFullName(), student.getGender(), student.getAge(), student.getPlaceOfBirth()); }
- When referencing fields, as in this.fullName
- As a reference passed to a method of some other object, as in otherObject.someMethod(this);
This third case is a bad practice because you are trying to use the current instance (this) before it is fully constructed. One can say “ but if it’s the last statement in the constructor, it’s fine!”
We can say that an instance is completely constructed only after the constructor completed ( exit of the constructor). So it doesn’t matter if this is the last statement in the constructor.