Thinking in terms of Objects with state and behavior

Com 3118 – Spring 2001

Deadline: 6.00pm, 2 April 2001

This assignment will not be graded, but it must be completed

as a part of the requirements for the course.

First, read the essay, "Plato’s Theory of Forms," in its entirety. Handouts of the essay will be provided in class, but the essay is available on the course web site under the heading "Notes".

Plato’s theory of forms is one of the most celebrated philosophical concepts of the ancient world. We computer scientists have embraced a similar architectural concept that is very important to a Java programmer: The Object Concept. It may be surprising to see that these two very similar concepts could arise in such different times, and as a result of such different intentions, but the reason for their similarity is clear. Both concepts arise out of a want to organize similar objects into a hierarchical structure that succinctly describes the relationship between types of objects. Both concepts claim that similar objects can be grouped into a class of objects that encapsulates the essence of the similarity between those objects.

The understanding and use of proper encapsulation

is an essential part of Java programming.

As introductory Java programmers, your interaction with the world of classes and objects will be simply functional. You will learn to encapsulate the form and behavior of a class of objects into a Java class. You will learn how to create instances of a given class of objects and cause them to interact in simple microworlds defined by Java programs. In this course you will rarely be required to reflect on the architecture of the hierarchical system itself. If you are intrigued by the philosophical implications of the object concept, I suggest a course in object-oriented design.

1. The article describes that Plato’s theory encompassed not only physical objects like tables and rocks, but also abstract ideas like beauty and justice. In Java, a class can be defined as concrete, abstract, or final-concrete. A class has a name, which by convention starts with a capital letter. (For a complete description of valid identifiers, see the description of data members below.)

Concrete classes roughly correspond with Plato’s physical objects like tables and rocks, because they can be instantiated. For instance, given the class definition:

public class Table {}

it is possible to create an object of type Table, also known as an instance of the class Table, using the new keyword:

Table desk = new Table();

Classes are concrete by default. In other words, a class is assumed to be concrete unless it is designated otherwise.

Abstract classes roughly correspond with Plato’s abstract ideas of beauty and justice, because they cannot be instantiated. In other words, given the class definition:

public abstract class Beauty {}

It would be illegal to try to create an object of class Beauty, because Beauty is merely an abstraction. Thus the following code would cause a compiler error:

Beauty sunset = new Beauty();

Abstract classes are designated by the keyword abstract.

Abstract and concrete classes have the quality that they can be subclassed. A subclass of a given class, also known as a derived class, inherits all of the qualities of the parent class and specifies qualities that separate the subclass from the parent. Such a parent class is known as the superclass for the classes that derive from it. For example, a class Sedan is a possible subclass of a class Automobile. Automobile would then be the superclass for the class Sedan. The ability of a class to encompass all of its subclasses and define qualities that are common to all of those subclasses is called polymorphism.

Polymorphism is implemented in the Java language through inheritance, which is designated by the extends keyword. For instance, the following class definition implements the relationship described above:

public class Sedan extends Automobile {}

Final concrete classes are concrete classes that cannot be further subclassed. There are only very specific advanced situations when a concrete class must be designated as a final class. There are many situations, however, where a concrete class could be designated as a final class. For example, in the first laboratory assignment, the following class definition is provided:

public final class IdentityFunction extends Function {}

The decision to designate this class as a final class is purely a design decision. In this case, there is no need to classify IdentityFunction objects into further subclasses with differing qualities, so it is appropriate to designate the class IdentityFunction as a final class. Instances of the class would have exactly the same behavior, however, if the class was concrete.

Final classes are designated by the final keyword.

 

 

As an exercise, provide an empty class description that correctly describes each of the following types of objects or concepts. It is safe to invent classes like Table or Automobile as superclasses for classes of objects. This is an exercise in design; you will not have to implement any of these classes. The first few are provided to get you started thinking in polymorphic terms.

 

Class Class Description

Sedan public class Sedan extends Automobile {} _______

Blue public abstract class Blue extends Color_{}_______

Basketball __________________________________________________

Screwdriver __________________________________________________

Piano __________________________________________________

Oxygen __________________________________________________

Happy __________________________________________________

 

2. Qualities of objects can be separated into two categories: form and behavior. The form of a class of objects encapsulates the types of qualities that separate objects of that class from objects of its superclass. In Java, this encapsulation is represented by a list of data members that represents the types of qualities common to objects of a given class. Each data member has an identifier, a type, an access modifier, and a default value. A data member is also known as an instance variable.

The identifier is the name of the data member, and can be any combination of letters, digits, and underscore characters that starts with a letter. Identifiers are case sensitive, which means that the identifiers abc and ABC are considered to be different. Identifiers cannot contain any spaces, so the standard convention for Java is to begin an identifier with a lowercase letter and capitalize the first letter of each subsequent word. For instance, these are all legal identifiers that follow convention:

color

size

firstName

leftoverLunchFromLastMonday

The following are illegal identifiers:

1stName

size*

leftover Lunch From Last Monday

The type is the class of the data member, and can be any public class or any one of the primitive types.

The access modifier for a data member designates the availability of the data member to objects of certain classes. The keyword private designates that only objects of the class being defined have access to the contents of the data member. The keyword protected designates that only objects of the class being defined and objects of subclasses of the class being defined have access to the contents of the data member. The keyword public designates that objects of any class have access to the contents of the data member. (Accessing a data member of an object is performed using the dot operator as described below.)

The default value for a data member can be any legal value or object of the type of the data member. If no default value is specified for a data member, its default value is set to 0 or false for a primitive type, or null for a reference type. The null keyword represents an object that has yet to be defined, i.e. an empty space to later store an object.

The following is a definition for a class containing three data members, one of which is an integer, one of which is a double-precision real number, and one of which is a Color object:

public class Pencil extends WritingImplement {

private int hardness = 2;

public double length = 4.71;

public Color color = new Color(0, 0, 0);

}

An instance p of class Pencil could be created through the use of the new keyword:

Pencil p = new Pencil();

The data member hardness, which is an integer value, could only be accessed within the class definition for Pencil, through the use of the symbol p.hardness. For example, the following line of code is legal only if it appears within the class definition for Pencil:

p.hardness = 1;

The data member length, which is a real number value, could be accessed within the class definition for Pencil or the class definition for a subclass of Pencil through the use of the symbol p.length. For example, the following line of code is legal only if it appears in the class definition for Pencil or the class definition for a subclass of Pencil:

p.length = 3.16;

The data member color, which is an object of type Color, could be accessed within any class definition through the use of the symbol p.color. For example, the following line of code is legal in any class definition:

p.color = new Color(255, 255, 255);

Each instance of a class can have different values for each of its data members. For example, one Pencil can have a hardness of 1, a length of 3.16, and an instance of Color corresponding with the color red, while another Pencil can have a hardness of 2, a length of 6.55, and an instance of Color corresponding with the color black.

A class is said to own its data members. Data members that are owned by a class can be accessed through the use of the this keyword. The prefix this. can be eliminated for owned data members within a class definition, as the prefix is implied by context. For example, the following lines of code are equal within the definition for class Pencil or the definition of a subclass of class Pencil, as a data member length would be owned by either class:

this.length = 5.25;

length = 5.25;

Data members can be designated static, final, or both static and final, if so desired. A data member is designated as static using the static keyword. A data member is designated as final using the final keyword. These designations are included between the access modifier and the type, like so:

public static int sharedInt = 4;

public final double constantDouble = 3.14;

public static final String text = "Goodbye, world.";

A data member that is designated static is shared by all instances of a class. A static data member is also called a class variable.

A data member that is designated final may not have its value changed. The value of a final data member is also known as a constant.

A data member that is designated as static and final is both shared and constant. Most data members that are designated as final are also designated as static, by convention. Designating a final data member as static is more efficient than not designating a final data member as static, because only one shared copy of the constant value is maintained, rather than multiple copies of the constant value. Identifiers for data members that are designated as static and final follow a different convention than other data members. It is common practice to use an all capital letter identifier with words separated by underscore characters for a static final data member. For example, a default value for the hardness data member of Pencil might be defined in the following fashion:

public static final int DEFAULT_HARDNESS = 2;

As a second exercise, fill in the following definition for a subclass of WritingImplement named Pen. The class is to have four data members:

DEFAULT_COLOR, an object of class Color representing the color black. This data member has been defined for you.

activated, a boolean variable representing whether or not the pen is ready to write, (i.e. the cap is off, or the button has been clicked that protrudes the ball point, &c.) This should be an instance variable accessible from any class definition. The default value should be false.

inkLeft, a double value representing the amount of ink left in the ink chamber of the pen, in units. This should be an instance variable accessible within the class definition for Pen and the definitions of any of its subclasses. The default value should be 10.0 units.

color, an instance of class Color representing the color of the ink in the ink chamber of the pen. This should be a constant class variable accessible only within the class definition for Pen. The default value should be DEFAULT_COLOR.

 

public class Pen _____________________________________________ {

public static final Color DEFAULT_COLOR = new Color(0,0,0);

 

________________________________________________________

 

________________________________________________________

 

________________________________________________________

}

 

3. The second major category for qualities of a class of objects is behavior. Behavior for a class of objects is defined as a list of messages that an instance of that class can respond to. In Java, these messages are called methods. Each method has an identifier, an access modifier, a return type, a parameter list, and a body. A method is also known as an instance method.

The identifier and access modifier are the same as for data members.

The return type is the type of value that the method will return when its computational task is completed. A method can return a value of any of the primitive types, or an object. A method that returns a reference type may return null. The void keyword designates that a method does not return a value.

The parameter list is a comma-separated list of types and identifiers that the method accepts as input for the computational task it performs. A method can accept zero or more parameters in any combination of primitive or reference types.

The body is a mini-program that performs some computational task. The statements that make up the computational task for a method are enclosed in braces.

The most elementary kind of method included in a class description is a constructor, which is used in conjunction with the new keyword to create instances of the class. A constructor is the only kind of method that does not have an identifier. The default constructor for a class accepts no parameters and creates an instance of the class that has default values for all of its data members. Other constructors accept one or more parameters and create an instance of the class with non-default values. A return statement is not required for a constructor, as it always returns an instance of the class. The following would be valid constructors for the Pencil class defined above:

public Pencil() {}

public Pencil(int h, double l, Color c) {

hardness = h;

length = l;

color = c;

}

Two other fundamental kinds of methods included in a class description are inspectors and mutators. An inspector accepts no parameters and returns the value of one of the data members for the object. A mutator accepts one parameter and changes the value of one of the data members to the value passed as a parameter. The identifier convention for an inspector is getMember, where Member is the name of the data member whose value is to be returned. (The convention for an inspector of a boolean value is isMember.) The identifier convention for a mutator is setMember, where Member is the name of the data member whose value is to be changed. The following would be a valid inspector and mutator pair for the hardness data member of class Pencil:

public void setHardness(int h) {

hardness = h;

}

public int getHardness() {

return hardness;

}

There is a technique used in object-oriented programming called data hiding. Data hiding involves designating all data members for a class as private, and allowing access to data member values through a programming interface. A programming interface is simply a method or group of methods that allow inspection and/or mutation of a single data member. Using data hiding, the accessibility of a data member is determined by the availability of an inspector and/or mutator for the data member, and the access modifiers for those methods.

We will be using the data hiding technique for every class we define,

except in very rare circumstances.

The remaining methods included in a class definition define the available behavior for an instance of the class. These methods are quite simply black boxes that perform some computational task. These black boxes may accept any number of parameters as input, and may return a value or object. These black boxes may or may not interact with the values of the data members, inspecting and/or mutating them as the computational task is performed.

Methods can be designated as abstract or static, if so desired. A data member is designated as abstract using the abstract keyword. A data member is designated as static using the static keyword. These designations are included between the access modifier and the return type of the method, like so:

public static void method() {}

public abstract void method();

An abstract method is one whose identifier, return type, parameter list, and access modifier is defined, but whose computational task is undefined. No method body is provided for an abstract method, as it is required that a subclass of the defined class will provide the method body. A class containing an abstract method cannot be instantiated, in the same regard as if it were designated as an abstract class.

A static method is one that is shared by all instances of the class. A static method may only interact with static data members of the class in which it is defined. A static method is also known as a class method.

As a final exercise, redefine the Pen class from above, using the data hiding technique. Attach a typewritten or neatly handwritten copy of your complete class definition.

• Include a default constructor and a constructor that accepts replacement values for each of the three data members.

• Provide a public programming interface for the data members of the class, i.e. a public inspector and public mutator for each data member.

• Include a publicly available abstract method named write, that accepts a parameter named s of type Surface.

• Include a class method named getDefaultColor that returns the DEFAULT_COLOR constant.