Learning Objects for Constructors
Concept The process of creating an object involves allocating memory for the object and assigning the reference to this block of memory to a variable.Constructors enable arbitrary initialization of the object during its creation.
These source code of these learning objects can be found in constructor.zip.
| LO | Topic | Java Files (.java) | Prerequisites |
| "What are constructors for?" | What are constructors for? | Constructor01A, B, C | |
| "Computation within constructors" | Computation within constructors | Constructor02 | 1 |
| "Overloading constructors" | Overloading constructors | Constructor03 | 2 |
| "Invoking an overloaded constructor from within a constructor" | Invoking another constructor | Constructor04 | 3 |
| "Explicit default constructors" | Explicit default constructors | Constructor05 | 3 |
| "Constructors for subclasses" | Constructors for subclasses | Constructor06A, B, C | 3 |
| "Constructors with object parameters" | Constructors with object parameters | Constructor07 | 3 |
| "Constructors with subclass object parameters" | Constructors with subclass | ||
| object parameters | Constructor08 | 6, 7 |
Program The example used in these LOs is class
Song with three fields: the name of the song, the length of the song in seconds and the pricePerSecond. The class is to be used to implement a website which charges for downloading the song; the price is the product of the length of the song in second and the price per second. To focus the discussion on constructors, the fields are not declared private.What are constructors for?
Concept An object is created by allocating memory for its fields. The fields are given the default values for their types. A reference to the object is returned and assigned to a variable; the reference can be used to access the fields and methods of the object.
Program: Constructor01B.java
// Learning Object Constructor01A
// what are constructors for?
class Song {
String name;
int seconds;
double pricePerSecond;
public double computePrice() {
return seconds * pricePerSecond;
}
}
public class Constructor01A {
public static void main(/*String[] args*/) {
Song song1 = new Song();
song1.name = "Waterloo";
song1.seconds = 164;
song1.pricePerSecond = 0.01;
double price = song1.computePrice();
}
}
If a constructor is not explicitly declared a default constructor is called.
- The variable
song1is allocated and contains the null value. - Memory is allocated for the fields of the object; this is displayed in the Instance and Array Area. Default values are assigned to the three fields.
- The default constructor is called but does nothing except return a reference to the object.
- The reference is stored in the variable
song1. - The reference in
song1is used to assign values to the fields of the object. - The reference in
song1is used to call the methodcomputePriceon the object; the method computes and returns the price, which is assigned to the variableprice.
Concept An explicit constructor method can be declared and used to initialize each object. The constructor method is identified by a special syntax: the name of the method is the same as the name of the class and there is no return type (because the value returned is of the type of the class itself).
Program: Constructor01B.java
// Learning Object Constructor01B
// what are constructors for?
class Song {
String name;
int seconds;
double pricePerSecond;
Song() {
name = "Waterloo";
seconds = 164;
pricePerSecond = 0.01;
}
public double computePrice() {
return seconds * pricePerSecond;
}
}
public class Constructor01B {
public static void main(/*String[] args*/) {
Song song1 = new Song();
double price = song1.computePrice();
}
}
This program is the same as the previous one except that the assignment of nondefault values to the fields of the object is moved to an explicit constructor.
- The variable
song1is allocated and contains the null value. - Memory is allocated for the fields of the object; this is displayed in the Instance and Array Area. Default values are assigned to the three fields.
- The constructor is called and assigns values to the three fields; then it returns a reference to the object.
- The reference is stored in the variable
song1. - The reference in
song1is used to call the methodcomputePriceon the object; the method computes and returns the price, which is assigned to the variableprice.
Exercise Add the creation of a second object
song2 to the program and verify that it is initialized to the same values.Concept Of course, it is highly unlikely that all objects created from a class will be initialized with the same values. A constructor can have formal parameters like any other method and is called with actual parameters.
Program: Constructor01C.java
// Learning Object Constructor01C
// what are constructors for?
class Song {
String name;
int seconds;
double pricePerSecond;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
}
public double computePrice() {
return seconds * pricePerSecond;
}
}
public class Constructor01C {
public static void main(/*String[] args*/) {
Song song1 = new Song("Waterloo", 164, 0.01);
double price = song1.computePrice();
}
}
This program is the same as the previous one except that the constructor has formal parameters and the actual parameters passed to the constructor are assigned to the fields of the object.
- The variable
song1is allocated and contains the null value. - Memory is allocated for the fields of the object; this is displayed in the Instance and Array Area. Default values are assigned to the three fields.
- The constructor is called with three actual parameters; these values are assigned to the formal parameters of the constructor method.
- The values of the formal parameters are assigned to the three fields; then the constructor returns a reference to the object.
- The reference is stored in the variable
song1. - The reference in
song1is used to call the methodcomputePriceon the object; the method computes and returns the price, which is assigned to the variableprice.
Exercise Modify the class so that the second parameter passes the number of minutes; the value of the field
seconds will have to be computed in the constructor.Computation within constructors
Concept Constructors are often used simply for assigning initial values to fields of an object; however, an arbitrary initializing computation can be carried out within the constructor.
Program: Constructor02.java
// Learning Object Constructor02
// computation within constructors
class Song {
String name;
int seconds;
double pricePerSecond;
double price;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
price = computePrice();
}
private double computePrice() {
return seconds * pricePerSecond;
}
}
public class Constructor02 {
public static void main(/*String[] args*/) {
Song song1 = new Song("Waterloo", 164, 0.01);
}
}
The price of a song will not change as long as the fields
second and pricePerSecond do not change; to avoid recomputing the price each time it is needed, the class contains a field price whose value is computed within the constructor. The method computePrice is declared to be private because it is needed only by the constructor.- The variable
song1is allocated and contains the null value. - Memory is allocated for the fields of the object and default values are assigned to the three fields.
- The constructor is called with three actual parameters; these values are assigned to the formal parameters of the constructor method and the values of the formal parameters are assigned to the three fields.
- The method
computePriceis called; it returns a value which stored in the fieldprice. - The constructor returns a reference to the object, which is stored in the variable
song1. The fieldpricecan be accessed to obtain the price of a song.
Exercise Modify the class so that no song has a price greater than two currency units.
Overloading constructors
Concept Constructors can be overloaded like other methods. A method is overloaded when there is more than one method with the same name; the parameter signature is used to decide which method to call. For constructors, overloading is usually done when some of the fields of an object can be initialized with default values, although we want to retain the possibility of explicitly supplying all the initial values.
Program: Constructor03.java
// Learning Object Constructor03
// overloading constructors
class Song {
String name;
int seconds;
double pricePerSecond;
double price;
final static double DEFAULT_PRICE = 0.005;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
price = computePrice();
}
Song(String n, int s) {
name = n;
seconds = s;
pricePerSecond = DEFAULT_PRICE;
price = computePrice();
}
private double computePrice() {
return seconds * pricePerSecond;
}
}
public class Constructor03 {
public static void main(/*String[] args*/) {
Song song1 = new Song("Waterloo", 164, 0.01);
Song song2 = new Song("Fernando", 253);
}
}
The website charges a uniform price per second for all songs, except for special offers. We define two constructors, one that specifies a price for special offers and another that uses a default price for ordinary songs.
- The value of the static constant
DEFAULT_PRICEis set as soon as the class is loaded and is displayed in the Constant area. - The variable
song1is allocated and contains the null value. - Memory is allocated for the four fields of the object and default values are assigned to the fields.
- The constructor is called with three actual parameters; the call is resolved so that the first constructor is executed. These values are assigned to the formal parameters of the constructor method and the values of the formal parameters are assigned to the three fields.
- The method
computePriceis called; it returns a value which stored in the fieldprice. - The constructor returns a reference to the object, which is stored in the variable
song1. - The computation is then repeated for
song2. Since the constructor is called with just two parameters (fornameandseconds), the second constructor is executed. The value of the fieldpricePerSecondis assigned from the constant, not from a parameter.
Exercise Modify the class to include a constructor with one parameter for the
name and with a default song length of three minutes.Exercise Modify the class to include a constructor with no parameters, so that all fields receive default values. Is there any meaning to the following constructor?
Song() {
}
Invoking an overloaded constructor from within a constructor
Concept Constructors can be overloaded like other methods. A method is overloaded when there is more than one method with the same name; the parameter signature is used to decide which method to call. For constructors, overloading is usually done when some of the fields of an object can be initialized with default values, although we want to retain the possibility of explicitly supplying all the initial values. In such cases, it is convenient to invoke one constructor from within another in order to avoid duplicating code. Invoking the method
this within one constructor calls another constructor with the appropriate parameter signature.Program: Constructor04.java
// Learning Object Constructor04
// invoking one constructor from another
class Song {
String name;
int seconds;
double pricePerSecond;
double price;
final static double DEFAULT_PRICE = 0.005;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
price = computePrice();
}
Song(String n, int s) {
this(n, s, DEFAULT_PRICE);
}
private double computePrice() {
return seconds * pricePerSecond;
}
}
public class Constructor04 {
public static void main(/*String[] args*/) {
Song song1 = new Song("Waterloo", 164);
}
}
The website charges a uniform price per second for all songs, except for special offers. We define two constructors, one that specifies a price for special offers and another that uses a default price for ordinary songs.
- The value of the static constant
DEFAULT_PRICEis set as soon as the class is loaded and is displayed in the Constant area. - The variable
song1is allocated and contains the null value. - Memory is allocated for the four fields of the object and default values are assigned to the fields.
- The constructor is called with two actual parameters; the call is resolved so that it is the second constructor that is executed.
- The two parameters, together with the default price, are immediately used to call the first constructor that has three parameters. The method name
thismeans: call a constructor from this class. This constructor initializes the first three fields from the parameters, and the value of the fourth field is computed by calling the methodcomputePrice. - The constructor returns a reference to the object, which is stored in the variable
song1.
Exercise Modify the class to include a constructor with one parameter, the name, and with a default song length of three minutes. Can this constructor call the two-parameter constructor which in turn calls the three-parameter constructor? Can a constructor call two other constructors, one after another?
Explicit default constructors
Concept When no constructor is explicitly written in a class, a default implicit constructor with no parameters exists; this constructor does nothing. If, however, one or more explicit constructors are given, there is no longer a constructor with no parameters. Should you want one, you have to write it explicitly.
Program: Constructor05.java
// Learning Object Constructor05
// explicit default constructors
class Song {
String name;
int seconds;
double pricePerSecond;
double price;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
price = computePrice();
}
Song() {
this("No song", 0, 0.0);
}
private double computePrice() {
return seconds * pricePerSecond;
}
}
public class Constructor05 {
public static void main(/*String[] args*/) {
Song song1 = new Song();
}
}
This program includes an explicit constructor with no parameters that calls the constructor with three parameters to perform initialization.
- The variable
song1is allocated and contains the null value. - Memory is allocated for the four fields of the object and default values are assigned to the fields.
- The constructor is called with no actual parameters; the call is resolved so that it is the second constructor that is executed.
- Three constant values are used to call the first constructor. The method name
thismeans: call a constructor from this class. This constructor initializes the first three fields from the parameters, and the value of the fourth field is computed by calling the methodcomputePrice. - The constructor returns a reference to the object, which is stored in the variable
song1.
Exercise Modify the class so that the constructor without parameters obtains initial values from the input.
Constructors for subclasses
Concept Constructors are not inherited. You must explicitly define a constructor for a subclass (with or without parameters). As its first statement, the constructor for the subclass must call a constructor for the superclass using the method
super.Program: Constructor06A.java
// Learning Object Constructor06A
// constructors for subclasses
class Song {
String name;
int seconds;
double pricePerSecond;
double price;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
price = computePrice();
}
private double computePrice() {
return seconds * pricePerSecond;
}
}
class DiscountSong extends Song {
double discount;
DiscountSong(String n, int s, double p, double d) {
super(n, s, p);
discount = d;
}
private double computePrice() {
return seconds * pricePerSecond * discount;
}
}
public class Constructor06A {
public static void main(/*String[] args*/) {
DiscountSong song1 = new DiscountSong("Waterloo", 164, 0.01, 0.8);
double price = song1.price;
}
}
The website wants to sell certain songs at a discount. The subclass
DiscountSong inherits from class Song, adds a field discount and overrides computePrice to includediscount in the computation. The constructor for the subclass calls the three-parameter constructor for the superclass, passing it the three parameters that it expects. The fourth parameter is used directly in the constructor DiscountSong to initialize the field discount.- The variable
song1is allocated and contains the null value. - Memory is allocated for the five fields of the object of the subclass
DiscountSongand default values are assigned to the fields. Four fields inherited from the superclass and one fielddiscountadded by the subclass. - The constructor for the subclass
DiscountSongis called with four parameters. It calls the constructor for the superclassSongwhich assigns values to three fields from the parameters and the fourth by callingcomputePrice. - The superclass constructor returns and then the fourth parameter of the subclass constructor is assigned to the field
discount. - The reference to the subclass object is returned and assigned to a variable
song1of that type.
Unfortunately, this does not do what we intended, because the superclass method for
computePrice is used to compute price instead of the method from the subclass.Exercise Could
song1 be declared to be of type Song? Explain your answer.Program: Constructor06B.java
// Learning Object Constructor06B
// constructors for subclasses
class Song {
String name;
int seconds;
double pricePerSecond;
double price;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
price = computePrice();
}
private double computePrice() {
return seconds * pricePerSecond;
}
}
class DiscountSong extends Song {
double discount;
DiscountSong(String n, int s, double p, double d) {
super(n, s, p);
discount = d;
price = computePrice();
}
private double computePrice() {
return seconds * pricePerSecond * discount;
}
}
public class Constructor06B {
public static void main(/*String[] args*/) {
DiscountSong song1 = new DiscountSong("Waterloo", 164, 0.01, 0.8);
double price = song1.price;
}
}
The problem can be solved by adding a call to
computePrice in the constructor for the subclass.Check this by executing the code and ensuring that the discounted price is computed.
The disadvantage of this solution is that we are calling
computePrice twice.Program: Constructor06C.java
// Learning Object Constructor06C
// constructors for subclasses
class Song {
String name;
int seconds;
double pricePerSecond;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
}
public double getPrice() {
return seconds * pricePerSecond;
}
}
class DiscountSong extends Song {
double discount;
DiscountSong(String n, int s, double p, double d) {
super(n, s, p);
discount = d;
}
public double getPrice() {
return seconds * pricePerSecond * discount;
}
}
public class Constructor06C {
public static void main(/*String[] args*/) {
Song song1 = new DiscountSong("Waterloo", 164, 0.01, 0.8);
double price = song1.getPrice();
}
}
Normally in an object-oriented program, all the fields of an object are private and an accessor method like
getPrice() is used to access the values of the fields. If this is done, the computation of the price can be placed in the accessor for the superclass and overridden in accessor for the subclass.Check this by executing the code and ensuring that the discounted price is computed.
The disadvantage of this solution is that the computation is performed for each access of the field
price.Exercise Develop other solutions for this problem: (a) Call
computePrice explicitly after the call to the constructor; (b) Modify getPrice to compute the value of price on the first call and save it for future calls. Summarize the advantages and disadvantages of all the solutions for this problem.Constructors with object parameters
Concept An object can contain fields of other user-defined objects, not just of primitive and predefined types. There is no difference in the constructors, except that references to objects are passed as actual parameters and assigned to fields of the object.
Program: Constructor07.java
// Learning Object Constructor07
// constructors with object parameters
class Song {
String name;
int seconds;
double pricePerSecond;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
}
public double computePrice() {
return seconds * pricePerSecond;
}
}
class SongSet {
public Song track1, track2;
public SongSet(Song t1, Song t2) {
track1 = t1; track2 = t2;
}
}
public class Constructor07 {
public static void main(/*String[] args*/) {
Song song1 = new Song("Waterloo", 164, 0.01);
Song song2 = new Song("Fernando", 253, 0.01);
SongSet set = new SongSet(song1, song2);
double price1 = set.track1.computePrice();
double price2 = set.track2.computePrice();
}
}
Two objects of type
Song are allocated and assigned to fields of another object of type SongSet which has two fields of type Song.- Execute the program until the two objects of type
Songare allocated and their references assigned to the variablessong1andsong2. (You may want to selectAnimation / Run Until (ctrl-T)to skip the animation of these declarations.) - A variable
setis allocated. An object of typeSongSetis allocated with default null fields. - The constructor for
SongSetis called and the references in the two variablessong1andsong2are passed as actual parameters. These references are stored in the two fieldstrack1andtrack2. - The reference to the object of class
SongSetis returned and stored inset. - The prices of the two objects are obtained and stored in the variables
price1andprice2.setis an object of typeSongset, whileset.track1is an object of typeSongand thus can be used to call the methodcomputePrice.
Exercise Modify the program so that the variables
song1 and song2 are not used; instead, the constructors for the songs are embedded within the constructor call for SongSet.Exercise Modify the program so the constructors for the songs are call within the constructor for
SongSet. Under what circumstances would this be done?Constructors with subclass object parameters
Concept An object of a subclass is also an object of the type of the superclass. Therefore, it can be used when an actual parameter is expected.
Program: Constructor08.java
// Learning Object Constructor08
// constructors with subclass object parameters
class Song {
String name;
int seconds;
double pricePerSecond;
Song(String n, int s, double p) {
name = n;
seconds = s;
pricePerSecond = p;
}
public double computePrice() {
return seconds * pricePerSecond;
}
}
class DiscountSong extends Song {
double discount;
DiscountSong(String n, int s, double p, double d) {
super(n, s, p);
discount = d;
}
public double computePrice() {
return seconds * pricePerSecond * discount;
}
}
class SongSet {
public Song track1, track2;
public SongSet(Song t1, Song t2) {
track1 = t1; track2 = t2;
}
}
public class Constructor08 {
public static void main(/*String[] args*/) {
Song song1 = new Song("Waterloo", 164, 0.01);
DiscountSong song2 = new DiscountSong("Fernando", 253, 0.01, 0.8);
SongSet set = new SongSet(song1, song2);
double price1 = set.track1.computePrice();
double price2 = set.track2.computePrice();
}
}
We allocate two objects, one of type
Song and one of type DiscountSong, and use them as actual parameters in the constructor for an object of type SongSet that expects two parameters of type Song.- Execute the program until the two objects one of type
Songthe other of typeDiscountSongare allocated and their references assigned to the variablessong1andsong2, respectively. (You may want to selectAnimation / Run Until (ctrl-T)to skip the animation of these declarations.) - The variable
setis allocated, and an object of typeSongSetis allocated with default null fields. - The constructor for
SongSetis called and the references in the two variablessong1andsong2are passed as actual parameters. These references are stored in the two fieldstrack1andtrack2. - The reference to the object of class
SongSetis returned and stored inset. - The prices of the two objects are obtained and stored in the variables
price1andprice2.setis an object of typeSongset, whileset.track1is an object of typeSongand thus can be used to call the methodcomputePriceof that class. Similarly forprice2, except thatset.track2is an object of typeDiscountSong; check that the methodcomputePriceof this class is called.
No comments:
Post a Comment