INFORMATION & COMPUTER SCIENCE DEPARTMENT, KFUPM

ICS201, SECTIONS 02  (002 Semester)

INTRODUCTION TO COMPUTER SCIENCE

LAB  #01 Further Object-Oriented Concepts

 

Instructor: Bashir M. Ghandi

Objectives:

To gain experience with:

 

 

1.  Designing with Inheritance

 

Inheritance is an important object-oriented concept that allows classes to be reused in order to define similar, but distinct, classes.  It also provides a mechanism for creating generalized solutions through polymorphism.

In this lab we walk through the development of a class hierarchy and a program that makes use of several classes in the hierarchy.

We begin by looking at three files which make up the inheritance hierarchy all of them in the cs.graphics package.

               Shape
               /     \
              /       \
           Line  Rectangle

Shape.java
This is the parent class.  It is not very useful as it stands, but it soon will be, even though we will not modify it directly at all.  Note the overloaded constructors, and the draw method that has no code in its definition.

package cs.graphics;

 

import java.awt.*;

 

/**

    Represents a generic shape, having a particular color.

*/

public class Shape {

   protected Color color;

 

   /**

       Defaults the color to black.

   */

   public Shape () {

      this.color = Color.black;

   }  // constructor Shape

 

   /**

       Specifies the color.

   */

   public Shape (Color color) {

      this.color = color;

   }  // constructor Shape

 

   /**

       Draws the shape.

   */

   public void draw (Graphics g) {

   }  // method draw

}  // class Shape

 

Line.java
The first child of Shape is Line.  Note that this class extends the Shape class.  Both classes have a draw method.

package cs.graphics;

 

import java.awt.*;

import java.awt.geom.*;

 

/**

    Represents a line of specific size and color, drawn at a particular location.

*/

public class Line extends Shape {

   private int x1, y1, x2, y2;

 

   /**

       Specifies starting and ending points, uses defaults color.

   */

   public Line (int x1, int y1, int x2, int y2) {

      super();

      this.x1 = x1;

      this.y1 = y1;

      this.x2 = x2;

      this.y2 = y2;

   }  // constructor Line

 

   /**

       Specifies starting and ending points, and color.

   */

   public Line (Color color, int x1, int y1, int x2, int y2) {

      super(color);

      this.x1 = x1;

      this.y1 = y1;

      this.x2 = x2;

      this.y2 = y2;

   }  // constructor Line

 

   /**

       Draws the line.

   */

   public void draw (Graphics g) {

      Graphics2D g2 = (Graphics2D) g;

      g2.setColor (color);

      g2.draw (new Line2D.Double(x1, y1, x2, y2));

   }  // method draw

}  // class Line

 

Review questions:

What is it called when two methods/constructors have the same name in a single class?

What is it called when a parent and child have methods with the same name and signature?

True/False:  Because Line is a child of Shape, Line objects will be able to do everything that Shape objects can do and more.

Why was the color field in the Shape class declared as protected?  What else could we use instead and what will be the effect?

 

Rectangle.java
This class is also derived from the Shape class.  It not only has color and starting coordinates, but also height and width. Note the similarities between the Rectangle class and the Line class.

package cs.graphics;

 

import java.awt.*;

/**

    Represents a rectangle of specific size and color, drawn in

    a particular location.

*/

public class Rectangle extends Shape {

   protected int x, y;

   protected int width, height;

 

   /**

       Specifies location and size, uses defaults color.

   */

   public Rectangle (int x, int y, int width, int height) {

      super();

      this.x = x;

      this.y = y;

      this.width = width;

      this.height = height;

   }  // constructor Rectangle

 

   /**

       Specifies location and size, and color.

   */

   public Rectangle (Color color, int x, int y, int width, int height) {

      super(color);

      this.x = x;

      this.y = y;

      this.width = width;

      this.height = height;

   }  // constructor Rectangle

 

   /**

       Draws the rectangle.

   */

   public void draw (Graphics g) {

      Graphics2D g2 = (Graphics2D) g;

      g2.setColor (color);

      g2.draw(new java.awt.Rectangle(x, y, width, height));

   }  // method draw

}  // class Rectangle

 

Review questions:

Why do we have to use the full name, java.awt.Rectangle, in creating the rectangle object in the draw method above?

What happens if we omit the call to super in the first constructor of the Rectangle class? 

What if the Shape class has only the second (not the default) constructor?

 

2.  Polymorphism

The following two classes, which could be stored in a single file RandomDraw.java in the cs.labs.lab01 package,  make use of the family of classes discussed above to implement an applet that draws random shapes.

Trace the code and make sure you understand everything about it.

package cs.labs.lab01;

 

import cs.graphics.*;

import java.applet.Applet;

import java.awt.Graphics;

import java.awt.Color;

import java.util.Random;

 

/**

  This applet creates and draws multiple random shapes.

*/

public class RandomDraw extends Applet {

   final int MAX_SHAPE = 20;

   Shape[] shapes = new Shape[MAX_SHAPE];

   ShapeCreator creator;

 

   /**

      Creates and stores multiple shapes.

   */

   public void init() {

      shapes = new Shape[MAX_SHAPE];

      creator = new ShapeCreator();

 

      for (int index = 0; index < MAX_SHAPE; index++) {

         shapes[index] = creator.newShape();

      }

   }  // method init

 

   /**

      Draws all of the shapes on the applet.

   */

   public void paint (Graphics g) {

      for (int index = 0; index < MAX_SHAPE; index++) {

         shapes[index].draw (g);

      }

   }  // method paint

}  // class RandomDraw

 

 

/**

   The ShapeCreator class contains code to create random shapes,

   each with random size, color, and location.

*/

class ShapeCreator {

   final int DIMENSION_MAX = 300; //maximum value of a dimension

   final int NUM_SHAPES = 2;  //different possible shapes(line & rectangle)

   final int LINE = 1;             //label for Line shape

   final int RECTANGLE = 2;   //label for Rectangle shape

   Random rand = new Random();

 

   /**

      Returns a random integer between 1 and max.

   */

   public int randomInt (int max) {

      return Math.abs(rand.nextInt()) % max + 1;

   }  // method randomInt

 

   /**

      Returns a random color created using random RGB values

   */

   public Color randomColor() {

      return new Color (rand.nextFloat(),rand.nextFloat(),rand.nextFloat());

   }  // method randomColor

 

   /**

       Returns a random shape with random characteristics.

   */

   public Shape newShape() {

      Shape result;

      int x1, y1, x2, y2, x, y, width, height;

      switch (randomInt(NUM_SHAPES)) {

         case LINE:

            x1 = randomInt (DIMENSION_MAX);

            y1 = randomInt (DIMENSION_MAX);

            x2 = randomInt (DIMENSION_MAX);

            y2 = randomInt (DIMENSION_MAX);

            result = new Line (randomColor(), x1, y1, x2, y2);

            break;

 

         case RECTANGLE:

         default:

            x = randomInt (DIMENSION_MAX);

            y = randomInt (DIMENSION_MAX);

            width = randomInt (DIMENSION_MAX);

            height = randomInt (DIMENSION_MAX);

            result = new Rectangle (randomColor(), x, y, width, height);

            break;

      }

      return result;

   }  // method newShape

}  // class ShapeCreator

 

Review questions:

The variable shapes is defined as an array of Shape objects (Shape[]). Yet what the ShapeCreator object stores into it are objects of class Line and Rectangle. How is this possible?

The paint method in the RandomDraw class calls the draw method of each object stored in the array. How is it that the correct shape is drawn even though the name of the method does not change.  What do we call this feature?

 

3.  Specifying classpath of user-defined packages for applets.

We saw in the last lab that to execute an application that makes use of user-defined packages, we specify the location of the package using the classpath option:

java –classpath “z://” cs.labs.lab00.TestPoint

 

Where the base package (cs) is in the root of the z dribe.

 

We pass similar parameter to JCreator to achieve the same result.

 

The problem now is how do we supply the classpath for applets?  -- recall applets are executed by loading their class file in an HTML file.

 

For applets, we specify the classpath for user-defined packages by using the codebase option of the APPLET tag in the HTML file.

The codebase specifies the location of the base package relative to the HTML file.  For example, if the HTML file is stored on the root of z drive, which is also where the base package (cs) is stored, then the following code should be used:

<APPLET codebase="." code=cs.labs.lab01.RandomDraw.class width=500 height=500>

</APPLET>

 

Notice that “.” means the current foldert (the folder containing the html file).  Thus, the command says, start looking for the cs package from the current folder.

 

If however, the HTML file is in the lab01 folder, then we need to use . . to point back to the root folder as follows:

<APPLET codebase="../../../" code=cs.labs.lab01.RandomDraw.class width=500 height=500>

</APPLET>

 

Open the file “RandomDraw.html” containing the above code from the lab01 folder and execute it to test the applet.

 

If the user-defined package is in a JAR file, we use the ARCHIVE option of the APPLET tag to specify the JAR file.

For example, if both the JAR file and the HTML file are in the same folder, we use the following:

<APPLET ARCHIVE = “cs.jar” codebase="." code=cs.labs.lab01.RandomDraw.class width=500 height=500>

</APPLET>

 

 

3.  Creating  java documentation for multiple packages.

 

In last lab, we learnt how to create Java documentation from a single source file.

We can create Java documentation for multiple packages by specifying the individual packages with the javadoc command.  For example, the following creates java documentation for all the packages we created so far:

javadoc –classpath “z://” cs.graphics cs.utilities cs.databases cs.labs.lab00 cs.labs.lab01

 

If the packages get too many, we can store them in a text file one package per line and execute the following form of the command:

javadoc –classpath “z://” @filename

 

where filename is the file containing the list of packages.

 

By default, the javadoc stores the HTML files it generates in the same folder containing the classes.  We can make it to store the files in another folder using the –d option.  For example, to store the HTML in a folder z://docs  we use the following:

javadoc –d “z://docs” –classpath “z://” cs.graphics cs.utilities cs.databases cs.labs.lab00 cs.labs.lab01

or

javadoc –d “z://docs” –classpath “z://” @filename

 


4.  Assignments

1.       Execute the HTML file of the RandomShape applet a few times and observe the output.  Generate the documentation for all the packages in a folder “docs” under your z drive.

 

2.        (a)   In a file called Ellipse.java, create a class called Ellipse derived from the Rectangle class.  You will observe that you do not need any additional variable in this case and the constructors only need to call the super constructor.  However, you need to override the draw method.

(b)   In a file called Square.java, create a class called Square derived from the Rectangle class.  The Square constructors should only accept one width dimension, since a square’s height and width are the same. Pass the width along to the parent’s constructor through a super call as both the height and width of the rectangle. Because the draw method of the Rectangle is sufficient for the square, there is no reason to override it this time.

(c)   Modify the CreateShape accordingly and compile and execute the applet.

 

3.        In the cs.databases package, write a class Worker and two subclasses, HourlyWorker and SalariedWorker.  Every worker has a name and salary rate.  Write a method computePay(int hours) that computes the weekly pay for every worker.  An hourly worker is paid according to the salary rate if the number of hours he worked is not more than 40.  However, every if he works more than 40 hours, the excess hours are paid at a rate of 1.5 times the normal rate.   The salaried worker is paid for 40 hours no matter the actual number of hours worked.  Write a static method that uses polymorphism to compute the pay of any Worker.  Supply a test program that tests these classes and methods.