Classes
What is a class?

A class is a grouping of objects that share the same set of applicable actions but differ in personality. A class is always given a name, such as Airplane. The personality of an object is known as local state in Java parlance and the actions are called methods.

  1. Real world example 1: Airplane. The personality of a particular object of class Airplane (also known as an airplane) includes: 1) the exterior paint scheme; 2) the pattern in which seats are arranged; 3) the number of seats; 4) many other such attributes which you can imagine (notice all the nouns). The actions associated with an airplane include: 1) take off; 2) land; 3) crash; 4) many other actions which you can imagine (notice all the verbs). The actions are common to all airplanes, but the local state of each airplane is different.

  2. Real world example 2: Person. The personality of a particular object of class Person (also known as a person) includes: 1) gender; 2) race; 3) experience in life; 4) height; 5) weight; 6) many other such attributes which you can imagine (notice all the nouns again). The actions associated with a person include: 1) eat; 2) sleep; 3) party; 4) walk; 5) run; 6) many other actions which you can imagine - some more pleasurable than others (notice all the verbs). The actions are common to all people, but the local state of each person is different.

  3. Java example 1: Double. The personality of a particular object of class Double (also known as a number) includes: 1) integer value; 2) fraction value. The actions associated with a number include: 1) multiply; 2) divide; 3) subtract; 4) add; 5) many other actions which you can imagine. The actions are common to all numbers, but the local state of each (that is, its value) is different.

  4. Java example 2: Vector. The personality of a particular object of class Vector (also known as a vector or list) includes: 1) objects stored in the list; 2) length of the list; 3) maybe some other attributes. The actions associated with a vector include: 1) insertion of a given object into the vector at some location with respect to the first object in the vector; 2) finding an object in the vector that matches a specification; 3) removing a found object from the vector; 4) maybe other actions which you can imagine. The actions are common to all vectors, but the local state of each (that is, its contents) is different.

Why do we need to use classes?

The world turns on classes (I just referenced another class, namely planet). Actually, we have been using classes all along but we did not tell you for fear that your brain would overheat and burn to a crisp. Java takes care of defining most important classes for us so we do not have to worry about building those classes. However, Java cannot anticipate every class we may need. So, Java gives us the tools to create our own classes to help us solve the problems concerning us.

How do we know what classes to build?

Consider defining a class for every type of object you can name that appears to be part of the problem at hand and for which a class is not already defined. Some will be obvious, some not. Try to imagine using the obvious ones. This should reveal requirements that make other necessary and/or useful classes obvious. Continue this refinement process to completion.

Consider the example of modeling waiting times at a doctor's office. In a doctor's office sick patients arrive and wait to be treated. When a doctor becomes available a patient is paired with the available doctor until treatment is completed and then the patient goes home and the doctor becomes available. We can identify the following classes immediately: patient, doctor, receptionist. Next we think about how these will be used. We might start by imagining a doctor's office with people waiting in first-come-first-served order to be paired with a doctor. This suggests defining a queue class which can be used by the receptionist to keep track of waiting patients and available doctors. We continue by noticing that the situation in the doctor's office changes only at particular points in time and that there are only three kinds of events that could cause a change: 1) a patient enters the office; 2) a patient leaves the office because treatment is completed and this frees a doctor; 3) a doctor enters the office. This suggests defining an event class. An event object would then have a type (three types were stated above) and a receptionist would act on an event differently for each type. But how would the receptionist receive an event to work with? A little thought makes evident the possibility that there may be many pending events at any one time so this suggests an eventList class, an object of which may be used to hold events and from which a receptionist could pick a "next event." The action of the receptionist will be to take an event from the eventList, record statistics, and generate a new list of events that should be put on the eventList. This suggests some handler of the events which we may call an eventListManager. The receptionist could do the eventlist handling on its own but its functionality is complicated enough (or at least it will be seen as such) so it is much better to outsource the eventlist handling to an eventListManager. Finally, we notice that the eventList and queue classes do essentially the same thing, the only difference being the order in which objects are removed. So, we merge the two into a single class called pritorityList.

Recap: For the doctor's office modeling problem we have identified the following classes to develop: Patient, Doctor, Receptionist, Event, PriorityList, and EventListManager. Next comes the development of these classes.

How do we build a class?

There are three things to worry about here: 1) Java syntax (what Java requires you to tell it); 2) personality definition (that is, local state); 3) action definition (that is, methods). Each is described in turn in separate subsections.

Java requirements:

  1. The body of a class definition is surrounded by a first line stating the name of the class, any class it extends, and any interfaces it implements and a last line which is }. For example,
       public class PriorityList {
          ...
          body goes here
          ...
       }
    
  2. There can be many classes defined in a file but only one can be "public" and if there is a public class in a file, the file prefix must be the same as the name of the public class.
  3. Java does not support multiple inheritance. Instead, objects of service classes are created and their methods invoked to supply needs in lieu of inheritance. To enforce the proper working of this arrangement the idea of interface was developed. Although it is possible to (directly, not through interface) inherit from no class, Java does allow inheritance from one super class. However, a class implementing an interface X is also considered of type X so object oriented principles are not sacrificed in any way.
  4. Local state is expressed as a collection of objects of various types. Each is defined type first. For example,
       public class PriorityList {
          Cell head, tail;
          DisplayFunc dispfn;
          int value;
          ...
       }
    
    which defines objects named head and tail of type Cell, an object named value of type int, and an object named dispfn of type DisplayFunc. DisplayFunc is actually an interface - depending on the type of objects stored by a PriorityList object the proper subclass of DisplayFunc will be installed as dispfn. The declaration for DisplayFunc is the following:
       interface DisplayFunc { void display(Object obj); }
    
    which means any class implementing DisplayFunc must define a method called display which takes an Object as argument and has no return value. An example of an implementation is as follows:
       class EventDisplay implements DisplayFunc {
          public void display (Object obj) {
             ((Event)obj).display();
          }
       }
    
    where it is assumed that the Event class will implement a display method. Cell is really a class; these objects are used to build hidden structures between stored objects so that removal is fast.
  5. The local state of an object of a class should be initialized when that object is created. This is done in a constructor. A class may have any number of constructors, including none (the default, where no initialization takes place, is then called). A constructor has a name matching the name of its class and any number of arguments. The body of a constructor assigns initial values to local state objects. For example,
       public class PriorityList {
          Cell head, tail;
          DisplayFunc dispfn;
          int value;
    
          public PriorityList (DisplayFunc d) {
             head = tail = null;
             dispfn = d;
          }
          ...
       }
    
    Thus, execution of
       PriorityList plist = new PriorityList(new EventDisplay());
    
    will create an EventDisplay object an install it in a newly created PriorityList object as dispfn.
  6. Actions on the local state are the result of invoking methods with are defined next. A method has a return value and an argument list. For example,
       public class PriorityList {
          ...
          public Object remove () {
             Object obj = getRoot();
             int val = valueOfLastNode();
             putRoot(popNode(),val);
             heapifyDown();
             return obj;
          }
          ...
       }
    
    defines a method called remove which takes no arguments and returns an object of type Object.

Defining personality:

  1. All of the personality attributes of a class are defined in the constructor.
  2. Attributes of a class are called fields. Each field is itself a member of a class and has a name.
  3. A field value is accessed or changed through a specified object and it is only that object whose field value is changed. The syntax required by Java is
       object.field = value;
    
    for changing the field value and
       value = object.field;
    
    for accessing the field.
  4. The following are constructors for the Event class, annotated to illuminate what is going on.
       // Constructor defining the event that a doctor
       // is paired with a patient.  Time to release is
       public Event (Doctor doctor, Patient patient) {
          doc = doctor;
          pat = patient;
          time = (int)Math.floor(Math.random()*1000);
       }
    
       // Constructor defining the event that a patient will
       // get sick.
       public Event (Patient patient) {
          doc = null;
          pat = patient;
          time = (int)Math.floor(Math.random()*1000);
       }
    
       // Constructor defining the event that a doctor joins the
       // doctor's pool.
       public Event (Doctor doctor) {
          doc = doctor;
          pat = null;
          time = 0;
       }
    

Defining methods (actions):

  1. One method is built for each action that can be applied to an object of a class. The developer of a class must consider carefully what actions on objects of that class need to be implemented. An action is carried out through manipulation of the local state of an object.
  2. For example, consider the PriorityList class. The purpose of a PriorityList object is to release an item contained in the PriorityList, upon demand, which has lowest value among all contained items. Implementation of a PriorityList with fast operations suggests a tree-like data structure for storing items. Since items should not know about the tree there should be another class called Cell for carrying contained items. Thus, it is reasonable to suppose that the local state for this class consists of at least one pointer to a Cell object. That Cell object should be the root of a balanced binary tree of some sort. Important actions on PriorityList objects would then be the insertion and removal of items from the tree. The append method could be used to insert a list of items into a PriorityList. When implementing append one notices the need to check for an empty list to head off the Java runtime error of trying to access an element that does not exist. This suggests implementing an empty method and using it in append. Further consideration leads to the implementation of an add method which is used to turn a PriorityList into a Queue.
  3. It is important to develop a display method for each class. Here is a display method for the Event class:
       void display () {
          if (doc != null) System.out.print(" Doctor: "+doc.ident());
          if (doc != null && pat != null) System.out.print(",");
          if (pat != null) System.out.print(" Patient: "+pat.ident());
          System.out.println(" (time: "+time+")");
       }