Start small
by Charles Kelemen
Under construction. Check back
in a week.
Here is our challange.
Suppose we are asked to help a college with a small part of its
data processing needs. The college has a file containing
records on students, staff, and faculty. Each record has
fields as follows:
- student fields: name, ID number, graduation year, advisor, dorm
- staff fields: name, ID number, months employed at college
- faculty fields: name, ID number, department, phone extension
Here is a small portion of the file:
stu William 183 1999 Kelemen Mertz
stf Don 640 12
stf Bill 643 12
stu Gabriel 180 2002 Kelemen Parrish
fac Kelemen 520 CS 8123
stu Brandon 176 2000 Kelemen ML
Each record in the file begins with a 3 letter code indicating
whether it is a student(stu), staff(stf), or faculty(fac) record.
The file is in no particular order.
We would like to be able to sort these records in different ways.
For example, we might want them all in ascending order by name for
a phone directory. we might want them in ascending order by
ID number for some other purpose.
We have developed a sort Sort.inssort
that can sort
any array of Sortable objects. So our task will be to make our
collection of Student, Faculty, and Staff objects into an
array of Sortable objects with an appropriate precedes methods for
the ordering we desire. We can redefine precedes for different orderings.
Looking at the fields of these records we notice that they all have a
name and ID number in common. This is a tip off that we should
define a superclass (we'll call it Person) that contains a name and ID
field. Then we will have classes Student, Staff, and Faculty be
subclasses of Person. If we make Person implement Sortable, then
any object of type Student, Staff, or Faculty may be considered
a member of the class Person or of the class Sortable. Then if we
define precedes methods in Student, Staff, and Faculty, we should be
able to use Sort.inssort
.
Now that we have the overall idea, we will begin to code. We do NOT
have to write all of this at once. In fact I recommend starting with
jaust a few lines of code and working in small increments. That is
provide enough scaffolding in your code to be able to know
what is going on. then compile, run,. and debug, in small increments.
This provides frequent positive feedback. The scaffolding can
be removed later.
So, how can we begin small? We could write just one of the subclasses,
work with it and then write the superclass and other subclasses.
Alternatively, we could write Person, work with it, and then write
the subclasses. We will do that latter.
Here is a start for the class Person (stored in file: Person.java):
thyme.cs.swarthmore.edu% cat Person.java
// Soon to be a suprclass, but now just a small class
// by cfk
//
import java.io.*;
class Person {
// protected data members....
protected String name;
protected int idnum;
// contructors
public Person() {name=""; idnum=0;}
public Person(String n, int id) {
name=new String(n);
idnum=id;}
// public MEMBER FUNCTIONS ...
// display
public void display() {
System.out.print(" Name: " + name + " ");
System.out.println(" Id: " + idnum);
}
}
Here is a small test program to try our Person class.
The test program is in the file: Trysubcl.java.
thyme.cs.swarthmore.edu% cat Trysubcl.java
// A program to help illustrate building subclasses starting small
// by cfk
// This example justs tests a class without any subclass
import java.io.*;
class Trysubcl {
public static void main(String argv[]) {
int idno;
String nm;
Person p1, p2; //declare a couple of Persons
System.out.println("starting: ");
// let's just try to create a couple of Persons using
// the constructor and display them using their display
//methods
idno=1; nm="Washington";
p1 = new Person(nm, idno); //instantiate a Person
idno=2; nm="Adams";
p2 = new Person(nm, idno); //instantiate a second Person
System.out.println("here are people");
p1.display();
System.out.println();
p2.display();
}
}
Putting these two files in a common directory and compiling lead to
a minor syntactical error. Because the files were so small, it was
easy to find the error and fix it. Then compiling and executing gave:
thyme.cs.swarthmore.edu% javac Trysubcl.java
thyme.cs.swarthmore.edu% java Trysubcl
starting:
here are people
Name: Washington Id: 1
Name: Adams Id: 2
In Trysubcl, we created two objects of type Person. Each object
was created using its own constructor. The class Person contains
an instance method display(). Each object used its own display()
method to create the output.
Let's now add the subclass Staff. After we get stuff working
for Staff, we can add Students and Faculty. The file Person.java
remains the same. Here is the file Staff.java and the slightly
updated Trysubcl.java.
thyme.cs.swarthmore.edu% cat Staff.java
//
// by cfk
import java.io.*;
class Staff extends Person
{
// private data members....
private int months;
// contructors
public Staff() {name=""; idnum=0; months=0;}
public Staff(String n, int id, int mo) {
name=new String(n); // name inherited from Person
idnum=id; //idnum inherited from person
months=mo;
}
// public MEMBER FUNCTIONS ...
// display
public void display() {
System.out.print(" Name: " + name);
System.out.print(" Id: " + idnum);
System.out.println(" Months: " + months);
}
}
thyme.cs.swarthmore.edu% cat Trysubcl.java
// A program to help illustrate building subclasses starting small
// by cfk
// We add the Class Staff which is a subclass of Person
import java.io.*;
class Trysubcl {
public static void main(String argv[]) {
int idno;
String nm;
Person p1, p2; //declare a couple of Persons
Staff s1, s2; // declare a couple of Staff
System.out.println("starting: ");
// let's just try to create a couple of Persons using
// the constructor and display them using their display
//methods
idno=1; nm="Washington";
p1 = new Person(nm, idno); //instantiate a Person
idno=2; nm="Adams";
p2 = new Person(nm, idno); //instantiate a second Person
// now let's create a couple of Staff objects
idno=85; nm="Franklin";
s1 = new Staff(nm, idno, 30); //instantiate a Staff
s2 = new Staff(new String("Jefferson"), 25, 7); // another Staff
System.out.println("here are people");
p1.display();
p2.display();
s1.display();
s2.display();
}
}
Here is the directory where these files reside and the results of
compiling and executing Trysubcl.java.
thyme.cs.swarthmore.edu% ls
Person.java Staff.java Trysubcl.java
thyme.cs.swarthmore.edu% javac Trysubcl.java
thyme.cs.swarthmore.edu% java Trysubcl
starting:
here are people
Name: Washington Id: 1
Name: Adams Id: 2
Name: Franklin Id: 85 Months: 30
Name: Jefferson Id: 25 Months: 7
Since Staff extends Person, s1 and s2 can be regarded as either
Staff objects or Person objects. This means that there are
two candidate display() methods that might be used at
s1.display(); Because the signatures are the same the
display() method in Staff 'overrides' the display() method in
Person. This is exactly what we want and the Staff objects
are displayed properly showing their months of service.
We are now ready to define a heterogeneous array. Since s1 and s2
can be regarded as Person objects, they can be stored in an array of
Person along with p1 and p2. Files Person.java and Staff.java
remain unchanged. Here is the new Trysubcl.java:
thyme.cs.swarthmore.edu% cat Trysubcl.java
// A program to help illustrate building subclasses starting small
// by cfk
// We add an array of Person holding references to both Staff objects
// and simple Person objects. This is a heterogeneous array.
import java.io.*;
class Trysubcl {
public static void main(String argv[]) {
int idno;
String nm;
Person p1, p2; //declare a couple of Persons
Staff s1, s2; // declare a couple of Staff
Person pers[]; //declare array of class Person
pers = new Person[4]; //instantiate array of references
// to Person objects
System.out.println("starting: ");
// let's just try to create a couple of Persons using
// the constructor and display them using their display
//methods
idno=1; nm="Washington";
p1 = new Person(nm, idno); //instantiate a Person
idno=2; nm="Adams";
p2 = new Person(nm, idno); //instantiate a second Person
// now let's create a couple of Staff objects
idno=85; nm="Franklin";
s1 = new Staff(nm, idno, 30); //instantiate a Staff
s2 = new Staff(new String("Jefferson"), 25, 7); // another Staff
pers[0] = p1;
pers[1] = p2;
pers[2] = s1; // Staff extends Person so this is ok.
pers[3] = s2;
System.out.println("here are people");
for (int i=0; i<4; i++)
pers[i].display();
}
}
Compiling and running this version leads to:
thyme.cs.swarthmore.edu% java Trysubcl
starting:
here are people
Name: Washington Id: 1
Name: Adams Id: 2
Name: Franklin Id: 85 Months: 30
Name: Jefferson Id: 25 Months: 7
This is the same result that we had before and what we wanted.
The output came from the loop:
for (int i=0; i<4; i++)
pers[i].display();
It is important to understand that even though pers[] is declared
to be an array of Person, the Java compiler and run time system
dynamically bind the appropriate display() method at each
invocation at execution
time. In this case pers[1] is a Person object and the
display() method declared in the class Person is used for pers[1].
pers[2] is a Staff object and the
display() method declared in the class Staff is used for pers[2].
Now that we have a small array, how can we sort it? Our
sort program works for arrays of Sortable objects. Copy
Sort.java and Sortable.java to your current directory. It
is important to note that we will make no changes to either
Sort.java or Sortable.java. We will change Person.java
by adding the phrase "implements Sortable" to the Class
declaration and providing the instance method
precedes((Object other). For the present we will define
precedes so that the sort will be by names in alphabetical
order. Here is the file Person.java.
thyme.cs.swarthmore.edu% cat Person.java
// a superclass for Student, Staff, and Faculty
// by cfk
//
import java.io.*;
class Person implements Sortable {
// protected data members....
protected String name;
protected int idnum;
// contructors
public Person() {name=""; idnum=0;}
public Person(String n, int id) {
name=new String(n);
idnum=id;}
// public MEMBER FUNCTIONS ...
//comparison
// use lexicographic order by name field
public boolean precedes(Object other) {
return(this.name.compareTo( ((Person) other).name) < 0);
}
// display
public void display() {
System.out.print(" Name: " + name + " ");
System.out.println(" Id: " + idnum);
}
}
We also alter Trysubcl.java, invoking Sort.inssort(pers, 4);
and printing the array before and after the sort.
thyme.cs.swarthmore.edu% cat Trysubcl.java
// A program to help illustrate building subclasses starting small
// by cfk
// We add an array of Person holding references to both Staff objects
// and simple Person objects. This is a heterogeneous array.
// Now we invoke Sort.inssort() on it.
import java.io.*;
class Trysubcl {
public static void main(String argv[]) {
int idno;
String nm;
Person p1, p2; //declare a couple of Persons
Staff s1, s2; // declare a couple of Staff
Person pers[]; //declare array of class Person
pers = new Person[4]; //instantiate array of references
// to Person objects
System.out.println("starting: ");
// let's just try to create a couple of Persons using
// the constructor and display them using their display
//methods
idno=1; nm="Washington";
p1 = new Person(nm, idno); //instantiate a Person
idno=2; nm="Adams";
p2 = new Person(nm, idno); //instantiate a second Person
// now let's create a couple of Staff objects
idno=85; nm="Franklin";
s1 = new Staff(nm, idno, 30); //instantiate a Staff
s2 = new Staff(new String("Jefferson"), 25, 7); // another Staff
pers[0] = p1;
pers[1] = p2;
pers[2] = s1; // Staff extends Person so this is ok.
pers[3] = s2;
System.out.println("here are people before sorting");
for (int i=0; i<4; i++)
pers[i].display();
Sort.inssort(pers, 4);
System.out.println("here are people after sorting");
for (int i=0; i<4; i++)
pers[i].display();
}
}
After compiling and executing we get:
thyme.cs.swarthmore.edu% java Trysubcl
starting:
here are people before sorting
Name: Washington Id: 1
Name: Adams Id: 2
Name: Franklin Id: 85 Months: 30
Name: Jefferson Id: 25 Months: 7
here are people after sorting
Name: Adams Id: 2
Name: Franklin Id: 85 Months: 30
Name: Jefferson Id: 25 Months: 7
Name: Washington Id: 1
As you can see Sort.inssort(pers, 4) has rearranged the pers[] array
so that all the people (both Staff and Person) are in lexicographic
order by name. Let's think about this a bit. Sort.inssort uses the
method precedes promised by the interface Sortable to compare
and order the elements of the array. The interface Sortable looks like:
public interface Sortable {
public boolean precedes(Object ob);
}
The parameter, ob, to precedes is an Object to make it as general
as possible. In Java, all classes (but not primitive types) are
subclasses of Object. To make Person 'implement' Sortable, we
must provide a method precedes in Person with exactly the same
signature. The method we used is:
public boolean precedes(Object other) {
return(this.name.compareTo( ((Person) other).name) < 0);
}
Since this method is in Person, we assume that the formal parameter
'other' can be cast to Person. A general Object may not have a name
field, but a Person object does. Thus, this.name is a String and
((Person) other).name is also a String so we can use the
String instance method compareTo to compare them.
To make sure you understand this, modify the precedes method
so that the sort arranges the people in descending order by
idnum. The only thing you should have to change is the
return line in the method precedes in the class Person.
We have been working in small increments and getting lots of CS highs
as we see things work. We can now move to implementing the subclasses
Student and Faculty or we can tackle file input. Let's do file input
first. We will ultimately want to be able to handle large
files of Student, Faculty, and Staff. But for now, let's just imagine
a small file like:
6
stf Jeff 651 9
per Timothy 101
per Jimmy 103
stf Don 640 12
stf Bill 643 12
per Gabriel 180
We have a design decision to make. Should the main program
do the input from the file and then use constructors to
put the data into the object's fields or should the main
program determine what kind of object and let an instance method
of the object complete the input? Either choice is reasonable, but
I like latter. So the main program will set up a StreamTokenizer
that will read from the file. For each record the main program
will determine whether it is a Person or Staff. The main program
will then create an object of the appropriate class and
invoke the file_in
instance method of that object. The only
change to the files Person.java and Staff.java is to add
the instance method
// file input
public void file_in(StreamTokenizer inf) throws IOException {
inf.nextToken(); name = inf.sval;
inf.nextToken(); idnum=(int)inf.nval;
}
to Person.java and the method
// file input
public void file_in(StreamTokenizer inf) throws IOException {
inf.nextToken(); name = inf.sval;
inf.nextToken(); idnum=(int)inf.nval;
inf.nextToken(); months = (int)inf.nval;
}
to the file Staff.java. With these changes to Person and Staff,
the following file Frysubcl.java will read in
and print out the file above.
thyme.cs.swarthmore.edu% cat Trysubcl.java
// A program to help illustrate building subclasses starting small
// by cfk
// We now introduce reading from a file into our heterogeneous
// array of Persons. The main program determines the kind
// of object a file record contains and the the an object
// instance of the appropriate class completes reading
// the record from the file.
//
import java.io.*;
class Trysubcl {
public static void main(String argv[]) throws IOException {
// Set up a StreamTokenizer associated with our input file
FileReader infi=new FileReader("students.txt");
StreamTokenizer infitok = new StreamTokenizer(infi);
infitok.eolIsSignificant(false);
int numofpeople; //the number of people in the file
String kindofperson; // the kind of person this line holds
System.out.println("starting: ");
infitok.nextToken(); numofpeople=(int)infitok.nval;
Person pers[]; //declare array of class Person
pers = new Person[numofpeople]; //instantiate array of references
// to Person objects
// read and print each record from the file
for (int i=0; i
thyme.cs.swarthmore.edu% cat students.txt
6
stf Jeff 651 9
per Timothy 101
per Jimmy 103
stf Don 640 12
stf Bill 643 12
per Gabriel 180
thyme.cs.swarthmore.edu% java Trysubcl
starting:
Name: Jeff Id: 651 Months: 9
Name: Timothy Id: 101
Name: Jimmy Id: 103
Name: Don Id: 640 Months: 12
Name: Bill Id: 643 Months: 12
Name: Gabriel Id: 180
thyme.cs.swarthmore.edu%
Now that we can read it in, we'll invoke our old sort without changes
to anything but the main program which now looks like:
thyme.cs.swarthmore.edu% cat Trysubcl.java
// A program to help illustrate building subclasses starting small
// by cfk
// We now introduce reading from a file into our heterogeneous
// array of Persons. The main program determines the kind
// of object a file record contains and the the an object
// instance of the appropriate class completes reading
// the record from the file.
//
import java.io.*;
class Trysubcl {
public static void main(String argv[]) throws IOException {
// Set up a StreamTokenizer associated with our input file
FileReader infi=new FileReader("students.txt");
StreamTokenizer infitok = new StreamTokenizer(infi);
infitok.eolIsSignificant(false);
int numofpeople; //the number of people in the file
String kindofperson; // the kind of person this line holds
System.out.println("starting: ");
infitok.nextToken(); numofpeople=(int)infitok.nval;
Person pers[]; //declare array of class Person
pers = new Person[numofpeople]; //instantiate array of references
// to Person objects
// read and print each record from the file
for (int i=0; i
After compiling and running, we get:
thyme.cs.swarthmore.edu% java Trysubcl
starting:
have read in people
Name: Jeff Id: 651 Months: 9
Name: Timothy Id: 101
Name: Jimmy Id: 103
Name: Don Id: 640 Months: 12
Name: Bill Id: 643 Months: 12
Name: Gabriel Id: 180
after sorting people
Name: Bill Id: 643 Months: 12
Name: Don Id: 640 Months: 12
Name: Gabriel Id: 180
Name: Jeff Id: 651 Months: 9
Name: Jimmy Id: 103
Name: Timothy Id: 101
thyme.cs.swarthmore.edu%
Now that we have file input and sorting working for objects of
Person and Staff, we will add the classes Students and Faculty.
thyme.cs.swarthmore.edu% cat Student.java
//
// by cfk
import java.io.*;
class Student extends Person
{
// private data members....
private String advisor, dorm;
private int gradyear;
// contructors
public Student() {name=""; gradyear=0;idnum=0;advisor="";dorm="";}
// public MEMBER FUNCTIONS ...
// display
public void display() {
System.out.print(" Name: " + name);
System.out.print(" Id: " + idnum);
System.out.print(" Grad year: " + gradyear);
System.out.print(" Advisor: " + advisor);
System.out.println(" Dorm: " + dorm);
}
// file input
public void file_in(StreamTokenizer inf) throws IOException {
inf.nextToken(); name = inf.sval;
inf.nextToken(); idnum=(int)inf.nval;
inf.nextToken(); gradyear=(int)inf.nval;
inf.nextToken(); advisor = inf.sval;
inf.nextToken(); dorm = inf.sval;
}
}
thyme.cs.swarthmore.edu% cat Faculty.java
//
// by cfk
import java.io.*;
class Faculty extends Person
{
// private data members....
private String dept;
private int phone;
// contructors
public Faculty() {name=""; idnum=0; dept=""; phone=0;}
// public MEMBER FUNCTIONS ...
// display
public void display() {
System.out.print(" Name: " + name);
System.out.print(" Id: " + idnum);
System.out.print(" Dept: " + dept);
System.out.println(" Phone: " + phone);
}
// file input
public void file_in(StreamTokenizer inf) throws IOException {
inf.nextToken(); name = inf.sval;
inf.nextToken(); idnum=(int)inf.nval;
inf.nextToken(); dept=inf.sval;
inf.nextToken(); phone= (int)inf.nval;
}
}
With these two new classes and by adding
if ( kindofperson.equalsIgnoreCase("stu") ) {
pers[i]=new Student(); //instantiate object
pers[i].file_in(infitok); // use objects file_in method to initialize
}
if ( kindofperson.equalsIgnoreCase("fac") ) {
pers[i]=new Faculty(); //instantiate object
pers[i].file_in(infitok); // use objects file_in method to initialize
}
to the input for-loop in Trysubcl.java, we can read in and sort
the file student.txt
thyme.cs.swarthmore.edu% cat students.txt
29
stu Nii 66 2002 smith Hollowell
fac Pete 567 English 8888
stu Laura 34 2000 Meeden Dana
fac Sue 535 Math 8887
stu Aaron 36 2001 Marshall Wharton
stu Bjorn 41 2001 Kelemen Palmer
stu Kellen 28 2002 Kelemen Pitt
stf Jeff 651 9
stu Timothy 101 2000 Kelemen Palmer
stu Jimmy 103 2001 Kelemen Parrish
stu Joshua 106 2000 Meeden ML
stu YingJie 108 2001 Meeden Parrish
fac Marshall 501 CS 8765
stu Will 113 2000 Kelemen Mertz
stu Benjamin 116 2002 Meeden ML
stu Benjamin 119 2001 Marshall Parrish
stu William 183 1999 Kelemen Mertz
stf Don 640 12
stf Bill 643 12
stu Gabriel 180 2002 Kelemen Parrish
fac Kelemen 520 CS 8123
stu Brandon 176 2000 Kelemen ML
stu Thomas 173 2002 Kelemen Parrish
stu Eugene 170 2001 Meeden Willets
stu Stephanie 168 2002 Marshall ML
stu Jeffrey 165 2001 Kelemen Mertz
stf Joan 677 9
stu Yuhai 164 2001 Kelemen Mertz
fac Meeden 530 CS 8333
We get:
thyme.cs.swarthmore.edu% java Trysubcl
starting:
have read in people
Name: Nii Id: 66 Grad year: 2002 Advisor: smith Dorm: Hollowell
Name: Pete Id: 567 Dept: English Phone: 8888
Name: Laura Id: 34 Grad year: 2000 Advisor: Meeden Dorm: Dana
Name: Sue Id: 535 Dept: Math Phone: 8887
Name: Aaron Id: 36 Grad year: 2001 Advisor: Marshall Dorm: Wharton
Name: Bjorn Id: 41 Grad year: 2001 Advisor: Kelemen Dorm: Palmer
Name: Kellen Id: 28 Grad year: 2002 Advisor: Kelemen Dorm: Pitt
Name: Jeff Id: 651 Months: 9
Name: Timothy Id: 101 Grad year: 2000 Advisor: Kelemen Dorm: Palmer
Name: Jimmy Id: 103 Grad year: 2001 Advisor: Kelemen Dorm: Parrish
Name: Joshua Id: 106 Grad year: 2000 Advisor: Meeden Dorm: ML
Name: YingJie Id: 108 Grad year: 2001 Advisor: Meeden Dorm: Parrish
Name: Marshall Id: 501 Dept: CS Phone: 8765
Name: Will Id: 113 Grad year: 2000 Advisor: Kelemen Dorm: Mertz
Name: Benjamin Id: 116 Grad year: 2002 Advisor: Meeden Dorm: ML
Name: Benjamin Id: 119 Grad year: 2001 Advisor: Marshall Dorm: Parrish
Name: William Id: 183 Grad year: 1999 Advisor: Kelemen Dorm: Mertz
Name: Don Id: 640 Months: 12
Name: Bill Id: 643 Months: 12
Name: Gabriel Id: 180 Grad year: 2002 Advisor: Kelemen Dorm: Parrish
Name: Kelemen Id: 520 Dept: CS Phone: 8123
Name: Brandon Id: 176 Grad year: 2000 Advisor: Kelemen Dorm: ML
Name: Thomas Id: 173 Grad year: 2002 Advisor: Kelemen Dorm: Parrish
Name: Eugene Id: 170 Grad year: 2001 Advisor: Meeden Dorm: Willets
Name: Stephanie Id: 168 Grad year: 2002 Advisor: Marshall Dorm: ML
Name: Jeffrey Id: 165 Grad year: 2001 Advisor: Kelemen Dorm: Mertz
Name: Joan Id: 677 Months: 9
Name: Yuhai Id: 164 Grad year: 2001 Advisor: Kelemen Dorm: Mertz
Name: Meeden Id: 530 Dept: CS Phone: 8333
after sorting people
Name: Aaron Id: 36 Grad year: 2001 Advisor: Marshall Dorm: Wharton
Name: Benjamin Id: 116 Grad year: 2002 Advisor: Meeden Dorm: ML
Name: Benjamin Id: 119 Grad year: 2001 Advisor: Marshall Dorm: Parrish
Name: Bill Id: 643 Months: 12
Name: Bjorn Id: 41 Grad year: 2001 Advisor: Kelemen Dorm: Palmer
Name: Brandon Id: 176 Grad year: 2000 Advisor: Kelemen Dorm: ML
Name: Don Id: 640 Months: 12
Name: Eugene Id: 170 Grad year: 2001 Advisor: Meeden Dorm: Willets
Name: Gabriel Id: 180 Grad year: 2002 Advisor: Kelemen Dorm: Parrish
Name: Jeff Id: 651 Months: 9
Name: Jeffrey Id: 165 Grad year: 2001 Advisor: Kelemen Dorm: Mertz
Name: Jimmy Id: 103 Grad year: 2001 Advisor: Kelemen Dorm: Parrish
Name: Joan Id: 677 Months: 9
Name: Joshua Id: 106 Grad year: 2000 Advisor: Meeden Dorm: ML
Name: Kelemen Id: 520 Dept: CS Phone: 8123
Name: Kellen Id: 28 Grad year: 2002 Advisor: Kelemen Dorm: Pitt
Name: Laura Id: 34 Grad year: 2000 Advisor: Meeden Dorm: Dana
Name: Marshall Id: 501 Dept: CS Phone: 8765
Name: Meeden Id: 530 Dept: CS Phone: 8333
Name: Nii Id: 66 Grad year: 2002 Advisor: smith Dorm: Hollowell
Name: Pete Id: 567 Dept: English Phone: 8888
Name: Stephanie Id: 168 Grad year: 2002 Advisor: Marshall Dorm: ML
Name: Sue Id: 535 Dept: Math Phone: 8887
Name: Thomas Id: 173 Grad year: 2002 Advisor: Kelemen Dorm: Parrish
Name: Timothy Id: 101 Grad year: 2000 Advisor: Kelemen Dorm: Palmer
Name: Will Id: 113 Grad year: 2000 Advisor: Kelemen Dorm: Mertz
Name: William Id: 183 Grad year: 1999 Advisor: Kelemen Dorm: Mertz
Name: YingJie Id: 108 Grad year: 2001 Advisor: Meeden Dorm: Parrish
Name: Yuhai Id: 164 Grad year: 2001 Advisor: Kelemen Dorm: Mertz
By working in small steps, we can now sort a heterogeneous array
of Person. Some of the objects are Students with 5 fields, some
Faculty with 4 fields, and some Staff with 3 fields. By introducing
more sophisticated precedes methods in the individual subclasses,
and exploiting the fact that Java will override the Person precedes
with a subclass precedes of the same signature, we can achieve
very sophisticated Sorts without changing our Sort method or anything
else in our classes. In order to do this we will use the
Java operator instanceof
. I ob is an object and Cls is a
class, then ob instanceof Cls
returns true if ob
is an instance of class Cls and return false otherwise. Suppose
we are interested in sorting our heterogeneous array of Person
as follows: Staff come first in alphabetical order by name;
Students come next in ascending order by Id number; Faculty
come last in alphabetical order by name. We can do this by
adding approptriate precedes methods to Staff, Student, and Faculty.
We will not change the files Sort, Sortable, Person, or Trysubcl.
Here is what we will add to Staff:
public boolean precedes(Object other) {
if (other instanceof Staff)
return(this.name.compareTo(((Staff)other).name) < 0);
else return(true);
}
Suppose st is a Staff object an ob is some other object (could be
Staff, Student, Faculty or something else). Then
st.precedes(ob)
will use the precedes method for the
Staff instance st (overridding the precedes in Person).
st.precedes(ob)
will check whether ob is also an
instance of Staff. If not, st.precedes(ob)
returns
true making st precede an object of any type other than Staff.
If ob is of type Staff, then the names are compared to determine
precedence. If the Staff objects were the only objects to
check precedence, then this would suffice to put all Staff objects
first. But Staff objects are NOT the only objects to check precedence.
Student and Faculty objects will also invoke precedes so we must
override the Person precedes in both Student and Faculty. Here is
precedes for Student:
public boolean precedes(Object other) {
if (other instanceof Student)
return (this.idnum< ((Student)other).idnum);
else if (other instanceof Staff) return(false);
else return(true);
}
Now suppose st is a Student object an ob is some other object (could be
Staff, Student, Faculty, or something else). Then
st.precedes(ob)
will use the precedes method for the
Student instance st (overridding the precedes in Person).
st.precedes(ob)
will check whether ob is also an
instance of Student. If so, st.precedes(ob)
determines precedence on the basis of ID numbers.
If not, st.precedes(ob)
returns false if ob is a
Staff object (making all Students come after Staff when a Student
object is doing the comparison). Finally if ob is not a Student
or a Staff object, st.precedes(ob)
returns
true making st precede any object of any type other than
Student or Staff (if a Student is doing the precedes).
So now, whether a Staff object or a Student object does the
precedes, Staff objects will precede Student objects. Staff objects
will determine precedence with other Staff objects by name. Student
objects will determine precedence with other Student objects by
ID number.
To complete our ordering we must override the Person precedes Faculty.
Here is
precedes for Faculty:
public boolean precedes(Object other) {
if (other instanceof Faculty)
return(this.name.compareTo(((Faculty)other).name) < 0);
else return(false);
}
Once these precedes methods are inserted into Staff, Student,
and Faculty, compiling and running Trysubcl leads to:
thyme.cs.swarthmore.edu% java Trysubcl
starting:
have read in people
Name: Nii Id: 66 Grad year: 2002 Advisor: smith Dorm: Hollowell
Name: Pete Id: 567 Dept: English Phone: 8888
Name: Laura Id: 34 Grad year: 2000 Advisor: Meeden Dorm: Dana
Name: Sue Id: 535 Dept: Math Phone: 8887
Name: Aaron Id: 36 Grad year: 2001 Advisor: Marshall Dorm: Wharton
Name: Bjorn Id: 41 Grad year: 2001 Advisor: Kelemen Dorm: Palmer
Name: Kellen Id: 28 Grad year: 2002 Advisor: Kelemen Dorm: Pitt
Name: Jeff Id: 651 Months: 9
Name: Timothy Id: 101 Grad year: 2000 Advisor: Kelemen Dorm: Palmer
Name: Jimmy Id: 103 Grad year: 2001 Advisor: Kelemen Dorm: Parrish
Name: Joshua Id: 106 Grad year: 2000 Advisor: Meeden Dorm: ML
Name: YingJie Id: 108 Grad year: 2001 Advisor: Meeden Dorm: Parrish
Name: Marshall Id: 501 Dept: CS Phone: 8765
Name: Will Id: 113 Grad year: 2000 Advisor: Kelemen Dorm: Mertz
Name: Benjamin Id: 116 Grad year: 2002 Advisor: Meeden Dorm: ML
Name: Benjamin Id: 119 Grad year: 2001 Advisor: Marshall Dorm: Parrish
Name: William Id: 183 Grad year: 1999 Advisor: Kelemen Dorm: Mertz
Name: Don Id: 640 Months: 12
Name: Bill Id: 643 Months: 12
Name: Gabriel Id: 180 Grad year: 2002 Advisor: Kelemen Dorm: Parrish
Name: Kelemen Id: 520 Dept: CS Phone: 8123
Name: Brandon Id: 176 Grad year: 2000 Advisor: Kelemen Dorm: ML
Name: Thomas Id: 173 Grad year: 2002 Advisor: Kelemen Dorm: Parrish
Name: Eugene Id: 170 Grad year: 2001 Advisor: Meeden Dorm: Willets
Name: Stephanie Id: 168 Grad year: 2002 Advisor: Marshall Dorm: ML
Name: Jeffrey Id: 165 Grad year: 2001 Advisor: Kelemen Dorm: Mertz
Name: Joan Id: 677 Months: 9
Name: Yuhai Id: 164 Grad year: 2001 Advisor: Kelemen Dorm: Mertz
Name: Meeden Id: 530 Dept: CS Phone: 8333
after sorting people
Name: Bill Id: 643 Months: 12
Name: Don Id: 640 Months: 12
Name: Jeff Id: 651 Months: 9
Name: Joan Id: 677 Months: 9
Name: Kellen Id: 28 Grad year: 2002 Advisor: Kelemen Dorm: Pitt
Name: Laura Id: 34 Grad year: 2000 Advisor: Meeden Dorm: Dana
Name: Aaron Id: 36 Grad year: 2001 Advisor: Marshall Dorm: Wharton
Name: Bjorn Id: 41 Grad year: 2001 Advisor: Kelemen Dorm: Palmer
Name: Nii Id: 66 Grad year: 2002 Advisor: smith Dorm: Hollowell
Name: Timothy Id: 101 Grad year: 2000 Advisor: Kelemen Dorm: Palmer
Name: Jimmy Id: 103 Grad year: 2001 Advisor: Kelemen Dorm: Parrish
Name: Joshua Id: 106 Grad year: 2000 Advisor: Meeden Dorm: ML
Name: YingJie Id: 108 Grad year: 2001 Advisor: Meeden Dorm: Parrish
Name: Will Id: 113 Grad year: 2000 Advisor: Kelemen Dorm: Mertz
Name: Benjamin Id: 116 Grad year: 2002 Advisor: Meeden Dorm: ML
Name: Benjamin Id: 119 Grad year: 2001 Advisor: Marshall Dorm: Parrish
Name: Yuhai Id: 164 Grad year: 2001 Advisor: Kelemen Dorm: Mertz
Name: Jeffrey Id: 165 Grad year: 2001 Advisor: Kelemen Dorm: Mertz
Name: Stephanie Id: 168 Grad year: 2002 Advisor: Marshall Dorm: ML
Name: Eugene Id: 170 Grad year: 2001 Advisor: Meeden Dorm: Willets
Name: Thomas Id: 173 Grad year: 2002 Advisor: Kelemen Dorm: Parrish
Name: Brandon Id: 176 Grad year: 2000 Advisor: Kelemen Dorm: ML
Name: Gabriel Id: 180 Grad year: 2002 Advisor: Kelemen Dorm: Parrish
Name: William Id: 183 Grad year: 1999 Advisor: Kelemen Dorm: Mertz
Name: Kelemen Id: 520 Dept: CS Phone: 8123
Name: Marshall Id: 501 Dept: CS Phone: 8765
Name: Meeden Id: 530 Dept: CS Phone: 8333
Name: Pete Id: 567 Dept: English Phone: 8888
Name: Sue Id: 535 Dept: Math Phone: 8887
This is what we wanted and we got it without using the same tried and
true Sort we developed for any Sortable object.