On completion of this section you will be familiar with
In non computing terms the word inheritance has two meanings. One meaning is acquiring money or property from a person – usually a relative – who has died. Another meaning occurs in biology and refers to the characteristics that children receive from their parents, through the medium of genes. A parent who is very tall is more likely to have tall children than a parent who is short. The tall parent passes to his children the genes that control the height and thus we say that the children inherit their height from their parent.
In computing the term inheritance is more akin to the biological meaning than the legal meaning. In computing, in order to have inheritance, we must have two classes - the parent class and the child class. Classes normally contain variables and methods. A child class simply inherits the methods and variables of its parent class. Thus a child class is the sum of its own variables and methods and the variables and methods of its parent.
If we were to design a class that processed data on a student then we would have data items such as student id, name, address, age, programme of study, fees. A patient in a hospital would have data items such as patient code, name address age, date of admission, nature of illness, name of doctor. A record for a car owner would have license number, name, address, age, motor resistration number, make, age of vehicle.
What we notice in all of the above examples is that they have name, address and age in common. Rather than repeating those data items in three separate classes, along with their get and set methods, we instead put them together into a single class called Person as shown in Listing 14.1 below.
Listing 14.1
|
1 |
public class Person |
|
2 |
{ |
|
3 |
private String name,address; |
|
4 |
private int age; |
|
5 |
public Person(){} |
|
6 |
public Person(String n, String a, int ag) |
|
7 |
{ |
|
8 |
name = n; |
|
9 |
address = a; |
|
10 |
age = ag; |
|
11 |
} |
|
12 |
public void setName(String n) |
|
13 |
{ |
|
14 |
name = n; |
|
15 |
} |
|
16 |
public void setAddress(String a) |
|
17 |
{ |
|
18 |
address = a; |
|
19 |
} |
|
20 |
public void setAge(int ag) |
|
21 |
{ |
|
22 |
age = ag; |
|
23 |
} |
|
24 |
public String getName() |
|
25 |
{ |
|
26 |
return name; |
|
27 |
} |
|
28 |
public String getAddress() |
|
29 |
{ |
|
30 |
return address; |
|
31 |
} |
|
32 |
public int getAge() |
|
33 |
{ |
|
34 |
return age; |
|
35 |
} |
|
36 |
public String toString() |
|
37 |
{ |
|
38 |
String msg; |
|
39 |
msg = "Name "; |
|
40 |
msg = msg.concat(name); |
|
41 |
msg = msg.concat("\nAddress "); |
|
42 |
msg = msg.concat(address); |
|
43 |
msg = msg.concat("\nAge "); |
|
44 |
msg = msg.concat(Integer.toString(age)); |
|
45 |
return msg; |
|
46 |
} |
|
47 |
} |
Apart from containing only the basic data exclusively associated with a person there is nothing remarkable about this class nor does any part of it require any explanation.
Below is an example of a child class of Person.
Listing 14.2
|
1 |
public class Student
extends Person |
|
2 |
{ |
|
3 |
private String sid, programme; |
|
4 |
private double fees; |
|
5 |
public Student(){} |
|
6 |
public Student(String n, String a, int ag, |
|
7 |
String id, String prg,
double f) |
|
8 |
{ |
|
9 |
super(n,a,ag); |
|
10 |
sid = id; |
|
11 |
programme = prg; |
|
12 |
fees = f; |
|
13 |
} |
|
14 |
public void setSID(String id) |
|
15 |
{ |
|
16 |
sid = id; |
|
17 |
} |
|
18 |
public void setProgramme(String prg) |
|
19 |
{ |
|
20 |
programme = prg; |
|
21 |
} |
|
22 |
public void setFees(double f) |
|
23 |
{ |
|
24 |
fees = f; |
|
25 |
} |
|
26 |
public String getSID() |
|
27 |
{ |
|
28 |
return sid; |
|
29 |
} |
|
30 |
public String getProgramme() |
|
31 |
{ |
|
32 |
return programme; |
|
33 |
} |
|
34 |
public double getFees() |
|
35 |
{ |
|
36 |
return fees; |
|
37 |
} |
|
38 |
public String toString() |
|
39 |
{ |
|
40 |
String msg; |
|
41 |
msg = super.toString(); |
|
42 |
msg = msg.concat("\nStudent id "); |
|
43 |
msg = msg.concat(sid); |
|
44 |
msg = msg.concat("\nProgramme "); |
|
45 |
msg = msg.concat(programme); |
|
46 |
msg = msg.concat("\nFees "); |
|
47 |
msg = msg.concat(Double.toString(fees)); |
|
48 |
return msg; |
|
49 |
} |
|
50 |
} |
Unlike the class Person, the class Student does require some explanation, beginning with its very signature at line 1. Here we notice that after the class’ name we have extends Person. This simply states that Student inherits Person. Thus the class Student, along with its own variables and methods will also contain all of the variables contained within the class Person. For this reason when we create an object of Student we will be at the same time creating an object of Person.
The variables exclusive to Student are declared in lines 3 and 4 and a blank constructor is on line 5. The constructor which spans lines 6 to 13 requires more detailed explanation. Remember that a constructor runs automatically when an object of its class is created. Again remember that when we create an object of a child class such as Student we also create an object of its parent class. Our constructor takes these into account. Thus its list of arguments contain sufficient data to populate the variables of both Person and Student. The first command of the constructor at line 9 uses the keyword super with the first three arguments in brackets after it. The meaning of this line could be translated into ordinary English as follows: run the constructor of the parent class and pass the values of n, a and ag to it. Of course for this to work we must ensure that the parent class has a constructor that takes three arguments of the type String, String, int.
We stated in the chapter on constructors that the constructor cannot ever be called directly. This is not exactly true. In our case here the constructor of a child class can call any of the constructors of the parent class using the keyword super.
The rest of the commands in the constructor, that is lines 10, 11 and 12 are simply normal processing that we have seen in early constructors.
The get and set methods of student also require no explanation but the method toString() does. Remember that this method is to print out the values of the variables that describe a student’s details. Those include the values of the variables in the Person class as well as those in the Student class. With this in mind lets examine toString which spans lines 38 – 49. It starts like its predecessor by declaring a local variable at line 40. At line 41 the initialization of this variable is msg = super.toString(). This translates into English as call the toString method of the parent class and store the returned value in msg. Thus once line 41 completes execution the variable msg will contain the personal details of the student, that is his name, address and age. The rest of the method simply concatenates the extra information from the Student object to the variable and the entire data is returned at line 48.
In order to complete our example of inheritance we have another class in Listing 14.3 which also inherits Person. This class is logically identical to that in Listing 14.2 and thus will not be further elaborated on here.
Listing 14.3
|
1 |
public class Employee
extends Person |
|
2 |
{ |
|
3 |
private String jobDescription, department; |
|
4 |
int yearsOfService; |
|
5 |
public Employee(){} |
|
6 |
public Employee(String n, String a, |
|
7 |
int ag, String jd, String
dpt, int yos) |
|
8 |
{ |
|
9 |
super(n,a, ag); |
|
10 |
jobDescription = jd; |
|
11 |
department = dpt; |
|
12 |
yearsOfService = yos; |
|
13 |
} |
|
14 |
public void setJobDescription(String jd) |
|
15 |
{ |
|
16 |
jobDescription = jd; |
|
17 |
} |
|
18 |
public void setDepartment(String dpt) |
|
19 |
{ |
|
20 |
department = dpt; |
|
21 |
} |
|
22 |
public void setYearsOfService(int yos) |
|
23 |
{ |
|
24 |
yearsOfService = yos; |
|
25 |
} |
|
26 |
public String getJobDescription() |
|
27 |
{ |
|
28 |
return jobDescription; |
|
29 |
} |
|
30 |
public String getDepartment() |
|
31 |
{ |
|
32 |
return department; |
|
33 |
} |
|
34 |
public int getYearsOfService() |
|
35 |
{ |
|
36 |
return yearsOfService; |
|
37 |
} |
|
38 |
public String toString() |
|
39 |
{ |
|
40 |
String msg; |
|
41 |
msg = super.toString(); |
|
42 |
msg = msg.concat("\nJob
Description "); |
|
43 |
msg = msg.concat(jobDescription); |
|
44 |
msg = msg.concat("\nDepartment "); |
|
45 |
msg = msg.concat(department); |
|
46 |
msg = msg.concat("\nYears of
Service "); |
|
47 |
msg =
msg.concat(Integer.toString(yearsOfService)); |
|
48 |
return msg; |
|
49 |
} |
|
50 |
} |
Now that we have our three classes completed let us look at how they could be used. Below in Listing 14.4 objects off all three are created and their variables are populated either using the constructors or the set methods.
Listing 14.4
|
1 |
public class Untitled1 |
|
2 |
{ |
|
3 |
public static void main(String[] args) |
|
4 |
{ |
|
5 |
Person p1, p2; |
|
6 |
Student s1, s2; |
|
7 |
Employee e1, e2; |
|
8 |
p1 = new Person(); |
|
9 |
p1.setName("Tom"); |
|
10 |
p1.setAddress("Tomville"); |
|
11 |
p1.setAge(12); |
|
12 |
p2 = new Person("Dick",
"Dixville",14); |
|
13 |
s1 = new Student(); |
|
14 |
s1.setName("Harry"); |
|
15 |
s1.setAddress("Hogsworth"); |
|
16 |
s1.setAge(16); |
|
17 |
s1.setSID("1234"); |
|
18 |
s1.setProgramme("Accounting"); |
|
19 |
s1.setFees(2000); |
|
20 |
s2 = new
Student("Annie","Annville", |
|
21 |
18,"3456","Management",2500); |
|
22 |
e1 = new Employee(); |
|
23 |
e1.setName("Maggie"); |
|
24 |
e1.setAddress("Maggstown"); |
|
25 |
e1.setAge(20); |
|
26 |
e1.setJobDescription("Lecturer"); |
|
27 |
e1.setDepartment("Information
Systems"); |
|
28 |
e1.setYearsOfService(5); |
|
29 |
e2 = new
Employee("Mary","Maryburough", |
|
30 |
22,"Accountant","Accountancy",10); |
|
31 |
System.out.println(p1.toString()); |
|
32 |
System.out.println(p2.toString()); |
|
33 |
System.out.println(s1.toString()); |
|
34 |
System.out.println(s2.toString()); |
|
35 |
System.out.println(e1.toString()); |
|
36 |
System.out.println(e2.toString()); |
|
37 |
} |
|
38 |
} |
At lines 5, 6 and 7 two pointers each are created for the classes Person, Student and Employee. In lines 8 – 11 an object of Person is created and its set methods are used to populate its variables. In line 12 another object of Person is created and its constructor is used to do the same job. So far nothing new. At line 13, however, a Student object is created and at lines 14 – 19 its set methods are used to populate its variables. Lines 14 – 16 call the methods setName, setAddress and setAge. Those methods don’t belong to the class Student but are inherited from the parent class Person. However, since they are inherited, then as far as the user of the class Student is concerned they are simply regarded as part of that class and can be called in exactly the same way as the methods that are native to Student. At line 20 an object of Student is created and its constructor is used to populate its variables. Notice that data that will populate both the Person part and the Student part is passed. (As we saw when we examined the class Student above all of the arguments will be passed to the constructor of the class Student. That constructor will pass the first three arguments to the constructor of Person and will populate its own variables with the last three arguments.)
In lines 21 – 30 two objects of Employee are created and populated in the same manners as the two objects of Student earlier.
Now we come to the output. At lines 31 an 32 the values of the variables in the two Person objects are printed using the toString method of those objects. In these two cases all that is called is that one single method. Thus we get the following output:
|
Name Tom |
|
Address Tomville |
|
Age 12 |
|
Name Dick |
|
Address Dixville |
|
Age 14 |
In lines 33 and 34, however, the contents of the two Student objects are printed. In those two lines the version of toString that are called is the version in the Student object. This will, however, call the version in the Person part first, which will output the details of the name, address and age. Then it will return control to the original method which will in turn concatenate the student id, programme and fees details and then return the combined result to be printed.
The output from those two lines appears below.
|
Name Harry |
|
Address Hogsworth |
|
Age 16 |
|
Student id 1234 |
|
Programme Accounting |
|
Fees 2000.0 |
|
Name Annie |
|
Address Annville |
|
Age 18 |
|
Student id 3456 |
|
Programme Management |
|
Fees 2500.0 |
Similar comments apply to lines 35 and 36, whose output is below.
|
Name Maggie |
|
Address Maggstown |
|
Age 20 |
|
Job Description Lecturer |
|
Department Information Systems |
|
Years of Service 5 |
|
Name Mary |
|
Address Maryburough |
|
Age 22 |
|
Job Description Accountant |
|
Department Accountancy |
|
Years of Service 10 |
Polymorphism is defined as a pointer to an object of a parent class can be used to point to objects of child classes of that parent class. In our case Person is the parent class of both Student and Employee and by this definition then a pointer to Person should be able to point to objects of both Student and Employee. In order to test this we shall modify the code in Listing 14.4 to that shown in Listing 14.5 below.
Listing 14.5
|
1 |
public class Untitled2 |
|
2 |
{ |
|
3 |
public static void main(String[] args) |
|
4 |
{ |
|
5 |
Person p1, p2; |
|
6 |
Person s1, s2; |
|
7 |
Person e1, e2; |
|
8 |
p1 = new Person(); |
|
9 |
p1.setName("Tom"); |
|
10 |
p1.setAddress("Tomville"); |
|
11 |
p1.setAge(12); |
|
12 |
p2 = new Person("Dick",
"Dixville",14); |
|
13 |
s1 = new Student(); |
|
14 |
s1.setName("Harry"); |
|
15 |
s1.setAddress("Hogsworth"); |
|
16 |
s1.setAge(16); |
|
17 |
//s1.setSID("1234"); |
|
18 |
//s1.setProgramme("Accounting"); |
|
19 |
//s1.setFees(2000); |
|
20 |
s2 = new
Student("Annie","Annville", |
|
21 |
18,"3456","Management",2500); |
|
22 |
e1 = new Employee(); |
|
23 |
e1.setName("Maggie"); |
|
24 |
e1.setAddress("Maggstown"); |
|
25 |
e1.setAge(20); |
|
26 |
//e1.setJobDescription("Lecturer"); |
|
27 |
//e1.setDepartment("Information
Systems"); |
|
28 |
//e1.setYearsOfService(5); |
|
29 |
e2 = new
Employee("Mary","Maryburough", |
|
30 |
22,"Accountant","Accountancy",10); |
|
31 |
System.out.println(p1.toString()); |
|
32 |
System.out.println(p2.toString()); |
|
33 |
System.out.println(s1.toString()); |
|
34 |
System.out.println(s2.toString()); |
|
35 |
System.out.println(e1.toString()); |
|
36 |
System.out.println(e2.toString()); |
|
37 |
} |
|
38 |
} |
The first change we notice here is that in lines 6 and 7 the pointers s1, s2, e1 and e2 have been changed to pointers to Person. Needless to say this does not effect the code in lines 8 – 12. A new Student object is created at line 13 and its address is quite happily stored in the pointer s1. Lines 14 – 16 also quite happily call the methods setName, setAddress and setAge. However we cannot call the methods setSID, setProgramme and setFees. The reason for this is that even though a pointer to a Student object can be stored in s1, s1 is still a pointer to Person and thus it cannot see any methods that are not defined in Person. The methods setSID, setProgramme and setFees are not defined in Person and therefore s1 cannot see them. Consequently the only methods of the child classes that can be called are the methods that it inherits from the parent class.
The same comments apply to Employee object at lines 22 – 28.
It does not effect any of the outputs in lines 31 – 36. The reason is that a toString method is declared in Person and the methods of the same name in the classes Student and Employee are said to override the method in the parent class. Thus in lines 33 and 34 it is the toString method of Student that is being called, while in lines 35 and 36 it is the method in Employee that is called.
So far polymorphism does not look very impressive, does it? The reason for that is that we have not put much forethought into the design of our classes. On the other hand if we consider that in all three classes we have the option of populating the class variables either through the constructor or else by having a single method to which we pass all of the values we wish to populate the object’s variables. Below therefore are our classes redesigned for more efficient use of polymorphism.
Listing 14.6
|
1 |
public class Person |
|
2 |
{ |
|
3 |
private String name,address; |
|
4 |
private int age; |
|
5 |
public Person(){} |
|
6 |
public Person(String n, String a, int ag) |
|
7 |
{ |
|
8 |
name = n; |
|
9 |
address = a; |
|
10 |
age = ag; |
|
11 |
} |
|
12 |
public void update(String[] values) |
|
13 |
{ |
|
14 |
name = values[0]; |
|
15 |
address = values[1]; |
|
16 |
age = Integer.parseInt(values[2].trim()); |
|
17 |
} |
|
18 |
public String toString() |
|
19 |
{ |
|
20 |
String msg; |
|
21 |
msg = "Name "; |
|
22 |
msg = msg.concat(name); |
|
23 |
msg = msg.concat("\nAddress "); |
|
24 |
msg = msg.concat(address); |
|
25 |
msg = msg.concat("\nAge "); |
|
26 |
msg = msg.concat(Integer.toString(age)); |
|
27 |
return msg; |
|
28 |
} |
|
29 |
} |
This is a severely cut down version of the previous class.
It is missing all of its set and get methods and the only methods that remain
are the constructors and the toString
method. One method has been added – update. This takes a String array as an argument and
its body simply copies the elements of the array argument into the appropriate
variables. Notice that the third element is first converted to int before being copied into the
variable ag.
Listing 14.7
|
1 |
public class Student
extends Person |
|
2 |
{ |
|
3 |
private String sid, programme; |
|
4 |
private double fees; |
|
5 |
public Student(){} |
|
6 |
public Student(String n, String a, int ag, |
|
7 |
String id, String prg,
double f) |
|
8 |
{ |
|
9 |
super(n,a,ag); |
|
10 |
sid = id; |
|
11 |
programme = prg; |
|
12 |
fees = f; |
|
13 |
} |
|
14 |
public void update(String[] values) |
|
15 |
{ |
|
16 |
super.update(values); |
|
17 |
sid = values[3]; |
|
18 |
programme = values[4]; |
|
19 |
fees =
Double.parseDouble(values[5].trim()); |
|
20 |
} |
|
21 |
public String toString() |
|
22 |
{ |
|
23 |
String msg; |
|
24 |
msg = super.toString(); |
|
25 |
msg = msg.concat("\nStudent id "); |
|
26 |
msg = msg.concat(sid); |
|
27 |
msg = msg.concat("\nProgramme "); |
|
28 |
msg = msg.concat(programme); |
|
29 |
msg = msg.concat("\nFees "); |
|
30 |
msg = msg.concat(Double.toString(fees)); |
|
31 |
return msg; |
|
32 |
} |
|
33 |
} |
Like its parent this class is also stripped of its get and set methods. It still retains its constructors as well as toString. It also has an update method. Since Student inherits Person it inherits its methods toString and update. However the original version of those two methods, only populates or displays the variables of Person and are therefore of limited use to the class Student. Consequently Student has to have its own version of those two methods. This is called overriding the methods. Thus the method update of the class Student at lines 14 – 20 overrides the update method of the class Person. The first action of the method, however, is to call the same method in its parent class using the super keyword at line 16. The entire array of the argument is passed up where the update of Person populates its own variables with the first three elements. Control now returns back to the update of Student where at lines 17 – 19 the fourth, fifth and sixth elements are copied into the objects variables.
Listing 14.8
|
1 |
public class Employee
extends Person |
|
2 |
{ |
|
3 |
private String jobDescription, department; |
|
4 |
int yearsOfService; |
|
5 |
public Employee(){} |
|
6 |
public Employee(String n, String a, |
|
7 |
int ag, String jd, String
dpt, int yos) |
|
8 |
{ |
|
9 |
super(n,a, ag); |
|
10 |
jobDescription = jd; |
|
11 |
department = dpt; |
|
12 |
yearsOfService = yos; |
|
13 |
} |
|
14 |
public void update(String[] values) |
|
15 |
{ |
|
16 |
super.update(values); |
|
17 |
jobDescription = values[3]; |
|
18 |
department = values[4]; |
|
19 |
yearsOfService =
Integer.parseInt(values[5].trim()); |
|
20 |
} |
|
21 |
public String toString() |
|
22 |
{ |
|
23 |
String msg; |
|
24 |
msg = super.toString(); |
|
25 |
msg = msg.concat("\nJob Description "); |
|
26 |
msg = msg.concat(jobDescription); |
|
27 |
msg = msg.concat("\nDepartment "); |
|
28 |
msg = msg.concat(department); |
|
29 |
msg = msg.concat("\nYears of
Service "); |
|
30 |
msg =
msg.concat(Integer.toString(yearsOfService)); |
|
31 |
return msg; |
|
32 |
} |
|
33 |
} |
The class Employee has been altered in exactly the same manner as the class Student and so there is no need to elaborate on it here.
Let us therefore look at Listing 14.9 below, where considerable alteration has taken place from its predecessor.
Listing 14.9
|
1 |
public class Untitled1 |
|
2 |
{ |
|
3 |
public static void main(String[] args) |
|
4 |
{ |
|
5 |
Person p1, p2; |
|
6 |
Person s1, s2; |
|
7 |
Person e1, e2; |
|
8 |
String personArray[] =
{"Tom","Tomville","12"}; |
|
9 |
String studentArray[] =
{"Harry","Hogsworth","16","1234", |
|
10 |
"Accounting","2000"}; |
|
11 |
String employeeArray[] =
{"Maggie","Maggstown","20", |
|
12 |
"Lecturer","Information Systems","5"}; |
|
13 |
p1 = new Person(); |
|
14 |
p1.update(personArray); |
|
15 |
p2 = new Person("Dick",
"Dixville",14); |
|
16 |
s1 = new Student(); |
|
17 |
s1.update(studentArray); |
|
18 |
s2 = new
Student("Annie","Annville", |
|
19 |
18,"3456","Management",2500); |
|
20 |
e1 = new Employee(); |
|
21 |
e1.update(employeeArray); |
|
22 |
e2 = new
Employee("Mary","Maryburough", |
|
23 |
22,"Accountant","Accountancy",10); |
|
24 |
System.out.println(p1.toString()); |
|
25 |
System.out.println(p2.toString()); |
|
26 |
System.out.println(s1.toString()); |
|
27 |
System.out.println(s2.toString()); |
|
28 |
System.out.println(e1.toString()); |
|
29 |
System.out.println(e2.toString()); |
|
30 |
} |
|
31 |
} |
We still have six pointers to object of the class Person. After those, at lines 8 – 11, we define three String arrays and insert values into the arrays’ elements that we will later pass to objects of our classes.
At line 13 we create an object of Person and at line 14 call its update method to update its variables. Instead of passing the actual values we pass an array that contains those values. There is no need to discuss the other Person object created at line 15.
At line 16 an object of Student is created and again at line 17 its update method is called and the larger array studentArray is passed to it. Remember that half of this array will be used to update the Person part of the object while the last part will be used to update the Student part.
The exact same comments apply to the Employee object.
An abstract class is a class of which we cannot create an object. So what is the purpose of having the class in the first place? The reason is that a class at the top level, whose data and methods may be common to a number of child classes, may not itself contain enough data to be useful in a practical application. An example of such a class is Person. It contains very little information that is of any use, but simply supplies common data for both Student and Employee.
In order to demonstrate the idea of abstract classes we shall make Person into one as shown below.
|
1 |
public abstract class Person |
There is no need to show any more of the class as the rest does not change. Similarly there is no need to show the other two classes as they simply inherit Person as before and remain unaware that it has been changed. In our main method, once we start creating objects of the classes, however, things start to change a little as shown in Listing 14.10 below.
Listing 14.10
|
1 |
public class Untitled1 |
|
2 |
{ |
|
3 |
public static void main(String[] args) |
|
4 |
{ |
|
5 |
Person p1, p2; |
|
6 |
Person s1, s2; |
|
7 |
Person e1, e2; |
|
8 |
String personArray[] =
{"Tom","Tomville","12"}; |
|
9 |
String studentArray[] =
{"Harry","Hogsworth","16","1234", |
|
10 |
"Accounting","2000"}; |
|
11 |
String employeeArray[] =
{"Maggie","Maggstown","20", |
|
12 |
"Lecturer","Information Systems","5"}; |
|
13 |
//p1 = new Person(); |
|
14 |
//p1.update(personArray); |
|
15 |
//p2 = new Person("Dick",
"Dixville",14); |
|
16 |
s1 = new Student(); |
|
17 |
s1.update(studentArray); |
|
18 |
s2 = new
Student("Annie","Annville", |
|
19 |
18,"3456","Management",2500); |
|
20 |
e1 = new Employee(); |
|
21 |
e1.update(employeeArray); |
|
22 |
e2 = new
Employee("Mary","Maryburough", |
|
23 |
22,"Accountant","Accountancy",10); |
|
24 |
//System.out.println(p1.toString()); |
|
25 |
//System.out.println(p2.toString()); |
|
26 |
System.out.println(s1.toString()); |
|
27 |
System.out.println(s2.toString()); |
|
28 |
System.out.println(e1.toString()); |
|
29 |
System.out.println(e2.toString()); |
|
30 |
} |
|
31 |
} |
Firstly we notice that we are allowed to create pointers to Person as indicated in lines 5 – 7. We are not, however, allowed to create objects of the class itself as shown in lines 13 – 15 where the previous statements are commented out. Also since no objects were created for either p1 or p2, lines 24 and 25 also have to be commented out.
Occasionally when designing a class system where polymorphism is expected to play a strong part we must ensure that the parent class contains definitions of all of the possible methods that the child classes may use. So far, in the class Person, all of the methods that we defined could perform some processing in that class. Thus update updated the class variables, while toString put the values of the same variables into a viewable String format. The child classes wanted to do the same thing as well as a little more. Therefore they overrode the methods mentioned above and called their parental versions using the super keyword.
There are times, however, when a parent class may have no idea what a child class may want to do with a method. As an example, the class Person could be inherited by any other class that deals with something that involves a human being. Apart from updating or printing out the contents of an object it would be very difficult to guess what a method called process would do in different child classes, as the processing would be entirely dependent on the child class. Consequently in Person no code could be provided. In this case the method could be declared as abstract. Listing 14.11 below shows the method inserted at line18. Apart from including the keyword abstract the next noticeable thing about it is that it does not contain a body, and – unlike any method that we have met so far – it finishes with a semi colon. Thus all that we are doing is telling any child class of Person that the method must be overridden and all that we are providing at the moment is the signature. The child must provide its own code.
Listing 14.11
|
1 |
public abstract class
Person |
|
2 |
{ |
|
3 |
private String name,address; |
|
4 |
private int age; |
|
5 |
public Person(){} |
|
6 |
public Person(String n, String a, int ag) |
|
7 |
{ |
|
8 |
name = n; |
|
9 |
address = a; |
|
10 |
age = ag; |
|
11 |
} |
|
12 |
public void update(String[] values) |
|
13 |
{ |
|
14 |
name = values[0]; |
|
15 |
address = values[1]; |
|
16 |
age = Integer.parseInt(values[2].trim()); |
|
17 |
} |
|
18 |
public abstract void process(String[]
args); |
|
19 |
public String toString() |
|
20 |
{ |
|
21 |
String msg; |
|
22 |
msg = "Name "; |
|
23 |
msg = msg.concat(name); |
|
24 |
msg = msg.concat("\nAddress "); |
|
25 |
msg = msg.concat(address); |
|
26 |
msg = msg.concat("\nAge "); |
|
27 |
msg = msg.concat(Integer.toString(age)); |
|
28 |
return msg; |
|
29 |
} |
|
30 |
} |
Listing 14.12 below implements its own version of the method process at lines 21 – 26 where it interprets the single value in the string as a double containing the amount that is to be deducted from the student’s outstanding fees.
Listing 14.12
|
1 |
Public class Student
extends Person |
|
2 |
{ |
|
3 |
private String sid, programme; |
|
4 |
private double fees; |
|
5 |
public Student(){} |
|
6 |
public Student(String n, String a, int ag, |
|
7 |
String id, String prg,
double f) |
|
8 |
{ |
|
9 |
super(n,a,ag); |
|
10 |
sid = id; |
|
11 |
programme = prg; |
|
12 |
fees = f; |
|
13 |
} |
|
14 |
public void update(String[] values) |
|
15 |
{ |
|
16 |
super.update(values); |
|
17 |
sid = values[3]; |
|
18 |
programme = values[4]; |
|
19 |
fees =
Double.parseDouble(values[5].trim()); |
|
20 |
} |
|
21 |
public void process(String[] args) |
|
22 |
{ |
|
23 |
double f; |
|
24 |
f = Double.parseDouble(args[0].trim()); |
|
25 |
fees -= f; |
|
26 |
} |
|
27 |
public String toString() |
|
28 |
{ |
|
29 |
String msg; |
|
30 |
msg = super.toString(); |
|
31 |
msg = msg.concat("\nStudent id "); |
|
32 |
msg = msg.concat(sid); |
|
33 |
msg = msg.concat("\nProgramme "); |
|
34 |
msg = msg.concat(programme); |
|
35 |
msg
= msg.concat("\nFees "); |
|
36 |
msg = msg.concat(Double.toString(fees)); |
|
37 |
return msg; |
|
38 |
} |
|
39 |
} |
Similarly in listing 14.13 at lines 21 – 26 the class Employee implements its own version of process where the three elements of the argument String are used to alter the values of the variables department, jobDescription and yearsOfService.
Listing 14.13
|
1 |
public class Employee
extends Person |
|
2 |
{ |
|
3 |
private String jobDescription, department; |
|
4 |
int yearsOfService; |
|
5 |
public Employee(){} |
|
6 |
public Employee(String n, String a, |
|
7 |
int ag, String jd, String
dpt, int yos) |
|
8 |
{ |
|
9 |
super(n,a, ag); |
|
10 |
jobDescription = jd; |
|
11 |
department = dpt; |
|
12 |
yearsOfService = yos; |
|
13 |
} |
|
14 |
public void update(String[] values) |
|
15 |
{ |
|
16 |
super.update(values); |
|
17 |
jobDescription = values[3]; |
|
18 |
department = values[4]; |
|
19 |
yearsOfService =
Integer.parseInt(values[5].trim()); |
|
20 |
} |
|
21 |
public void process(String[] args) |
|
22 |
{ |
|
23 |
jobDescription = args[0]; |
|
24 |
department = args[1]; |
|
25 |
yearsOfService =
Integer.parseInt(args[2].trim()); |
|
26 |
} |
|
27 |
public String toString() |
|
28 |
{ |
|
29 |
String msg; |
|
30 |
msg = super.toString(); |
|
31 |
msg = msg.concat("\nJob
Description "); |
|
32 |
msg = msg.concat(jobDescription); |
|
33 |
msg = msg.concat("\nDepartment "); |
|
34 |
msg = msg.concat(department); |
|
35 |
msg = msg.concat("\nYears of
Service "); |
|
36 |
msg = msg.concat(Integer.toString(yearsOfService)); |
|
37 |
return msg; |
|
38 |
} |
|
39 |
} |
Finally Listing 14.14 below shows how the altered classes can be used.
Listing 14.14
|
1 |
public class Untitled1 |
|
2 |
{ |
|
3 |
public static void main(String[] args) |
|
4 |
{ |
|
5 |
Person s, e; |
|
6 |
String studentArray[] =
{"2000"}; |
|
7 |
String employeeArray[] = {"Senior
Lecturer","ITS","6"}; |
|
8 |
s = new
Student("Annie","Annville", |
|
9 |
18,"3456","Management",2500); |
|
10 |
e = new
Employee("Mary","Maryburough", |
|
11 |
22,"Accountant","Accountancy",10); |
|
12 |
System.out.println(s.toString()); |
|
13 |
System.out.println(e.toString()); |
|
14 |
s.process(studentArray); |
|
15 |
e.process(employeeArray); |
|
16 |
System.out.println(s.toString()); |
|
17 |
System.out.println(e.toString()); |
|
18 |
} |
|
19 |
} |
In computing the word inheritance is quite similar to the same word when used
in biology i.e. children inherit characteristics from their parents.
If we have a number of classes that have a reasonable amount of data in common
it is a good practice to group the common data into a separate class which
becomes the parent class. This parent class, as well as containing data, can
also have methods for processing the data in that class.
Another class that requires the data and methods in the parent class can inherit
that class. This class now becomes the child class of the parent class. The
child, as well as having its own data and methods, will also have access to
the data and methods of the parent class.
In some cases the data contained in a parent class may not be sufficient for
a real application and therefore creating objects of it may not be practical.
If this is the case then we can declare this class as being abstract which
means that we cannot create objects of it. We can, however, create objects
of classes that inherits this abstract class, provided that those child classes
are not themselves declared as being abstract.
When creating an abstract class, the programmer may wish to insist that all
child classes will have certain methods for processing the data, but will
have no idea what type of processing those child classes will perform. In
this case the methods can be declared as abstract. An abstract method will
have return types and arguments but will have no code. All child classes of
this class must provide code for those methods, unless they are abstract classes
themselves.
Copy listings 14.1, 14.2, 14.3 and 14.4 into a new project, then compile and
run the application.
The class that process the sales must inherit this class and must store the
name and address of the customer to the file along with the sales data.