Doesn't it seem a little repetitive to call the method incNumStudents() every time we instantiate a new Student object ? Wouldn't it be nice if this was done 'automatically'? Well, it can be done. And much more.
Recall what the following statements mean:
Student s1; s1 = new Student();
The statement Student s1; allocates some space in the run-time stack for the reference s1. The statement s1 = new Student(); tells the compiler that it should consult our class definition for Student and issue instructions to allocate the appropriate memory; new is a keyword of the Java language meaning allocate new memory, and the class definition for Student is the recipe to use to do the allocation.
Well, this isn't the whole story. This is certainly what happens by default, but we can make other things happen as well. We can tell the compiler to issue instructions to do other things as well every time a new object is instantiated. We do this by defining a constructor.
A constructor is a kind of method which is similar to other methods that we've seen, except that technically it's not a member of the class, and it gets executed every time we instantiate a new object (for example, every time new is used). However, it looks like the member of a class, and behaves roughly like a member of a class; to understand why it's not a member, we'll have to wait a while until we know a bit more. One important difference between a constructor and an instance method (non-static method) is that a constructor can't return a value. It can have a return statement in it, but that return statement can't return any value. In addition, a constructor is named after the class.
Like other methods, a constructor can take parameters. Since the constructor is executed every time we instantiate a new object, this can be very useful for initializing the member variables of the object to values we pass as arguments to the constructor.
Another very common use for a constructor is to count the number of objects of a class that we have instantiated so far. In our case, let's say we're writing a registration program, and we want to keep track of the number of students that we've processed so far. To do this most elegantly, we'd do the following (compare to the code of the last section!):
public class Student { public void PayFees(double someamount) { feesOwing = feesOwing - someamount; } public Student(){ numStudents++; } public static int getNumStudents(){ return numStudents; } private static int numStudents = 0; private String name; private int age; private String courses; private double feesOwing = 5000.00; private boolean scholarship; }
Note that we've removed the method incNumStudents() and put a constructor in its place: Student().
Now if we execute the following program, the output is the same as before!
public class ProgWithStatic { public static void main(String[] args) { System.out.println(``There are `` + getNumStudents() + `` students registered.''); Student s1 = new Student(); Student s2 = new Student(); Student s3 = new Student(); System.out.println(``There are `` + getNumStudents() + `` students registered.''); } }
This give us
There are 0 students registered. There are 3 students registered.
This is clearly more elegant as we don't have to call the method incNumStudents() every time we instantiate a new Student object.
What would our constructor look like if we were to initialize all the member variable using it?
public class Student { public void PayFees(double someamount) { feesOwing = feesOwing - someamount; } public Student(String somename, int someage, String somecourses, double somefees, boolean someschol){ numStudents++; name = somename; age = someage courses = somecourses; feesOwing = somefees; scholarship = someschol; } public static int getNumStudents(){ return numStudents; } private static int numStudents = 0; private String name; private int age; private String courses; private double feesOwing = 5000.00; private boolean scholarship; }
And what would the call to the constructor look like to instantiate a new Student object?
public class ProgWithStatic { public static void main(String[] args) { System.out.println(``There are `` + getNumStudents() + `` students registered.''); Student s1 = new Student(``Fred Flintstone'', 35, ``CSC108'', 5327.23, false); Student s2 = new Student(``Wilma Flintstone'', 33, ``CSC108'', 5327.23, true); Student s3 = new Student(``Barney Rubble, 34, ``CSC108'', 5327.23, false); System.out.println(``There are `` + getNumStudents() + `` students registered.''); } }
This way we would instantiate 3 new objects, and each would have its member variables initialized to the respective values which appear as arguments in the call to the constructor. Initializing variables whenever memory is allocated (whether they are local or instance variables) is a very good habit to get into.