CS46A Lab

Inheritance

Copyright © Cay S. Horstmann 2009 Creative Commons License
This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 United States License.

In this lab, you will work in groups of two.

Put the answers to the questions in each step into the lab report. Copy/paste the programs that you write in the lab.

This icon indicates optional tasks. Do those if you have time.

Part A: Clocks

  1. Unzip this project somewhere. Start Netbeans (not BlueJ), select File -> Open Project, and choose the directory into which you unzipped the file. Look at the ClocksComponent class. In its paintComponent method, add a loop that draws all clocks in the clocks array list. Run the program. What happens?
  2. Now we want to put inheritance to work. It is not so nice that we can't tell whether a clock shows AM or PM. We want to draw the clock with a yellow background in the day and a blue background at night. But we don't want to change the Clock class. Instead, we will use inheritance.

    Make a new class ColoredClock that extends Clock. In the ClocksComponent, change one of the two clocks to ColoredClock. Compile and run. (To make a new class in Netbeans, go to in the Project tree at the left, expand the project, then Source Packages, right-click on the "default package" icon, then select New -> Java class.)

  3. Of course, nothing has changed yet. We need to override the draw method. Add a draw method to the ColoredClock class. To get started, let's draw a yellow background:
    public void draw(Graphics2D g2)
    {
       Color c = Color.YELLOW;
       g2.setColor(c);
       g2.fill(getBounds());
       g2.setColor(Color.BLACK);
    }

    (The getBounds method returns the rectangle bounding the clock.)

    Run your program. What happens?

  4. You got the background for our improved clock, but we lost something important—the clock itself. How do you get the clock to draw itself? Hint: super.
  5. Now we want the background to change depending on the time. Call getHours to get the current hours. If they are between 6 (inclusive) and 18 (exclusive), then draw a yellow background. Otherwise, draw a blue background. Compile and run. What is your code?
  6. Unfortunately, you'd have to wait for a while to test that your code works. We'll fake this as follows. The update method updates the current time. Let's override it so that it adds 12 to the hours:
    public void update()
    {
       super.update();
       hours = (hours + 12) % 24;
    }

    Compile. What happens? Why?

  7. Now use the public interface of the Clock class to fix this method. Compile and run. What happens?

    When you are done, remove that update method (or comment it out by surrounding it with /* and */).

  8. Make the background a circle instead of a rectangle.
  9. You just saw how to use inheritance to change the behavior of an existing class. Now we want to make a clock with a more significant change: to show the time anywhere in the world. (Ok, not quite anywhere. We ignore those places that have fractional offsets such as New Delhi, which is 13 1/2 hours earlier than San Francisco.)

    A WorldClock differs from a Clock in two ways:

    Make a class WorldClock that extends Clock. Add instance variables label and offset. Make a constructor that sets them. Add a new WorldClock("New York", -3) and new WorldClock("London", -8) to the ClocksComponent. Compile and run.

  10. Of course, the label doesn't yet show up. We need to draw it. Make a draw method of WorldClock that contains a call
    Rectangle bounds = getBounds();
    double x = bounds.getX();
    double y = bounds.getY();
    g2.drawString(label, (int) x, (int) y);

    Compile and run. What happens? (If one of the labels doesn't show up, move the clock down a bit.)

  11. Fix the draw method so that it shows the time and the label.
  12. Now we need to adjust for the time offset. Use step 6 as a guidance, but add the time offset. Compile and run your program. Your clocks should now show the correct local time. Attach a screen capture to your lab report.
  13. In the update method, protect against taking the % of a negative number. For example, if it is currently 6:00 in San Francisco, the time in London is 21:00, but (6 - 9) % 24 would be -3. Fix this and test by calling the toString method.
  14. Fix the draw method so that the label shows up below the clock.
  15. Make the world clocks colored. (Hint: This is a one-line change.)
  16. Deal with those fractional offsets. Supply the hours and minutes of the offset in the WorldClock constructor.

Part B: Actors

  1. Unzip this project somewhere. Open it with Netbeans. This is an Alice project. Run it and observe that the Robot travels across the sandy plain, dropping a trail of beepers.

    Observe that the beepers slowly fade.

    Now look at the code. Note that both Robot and Beeper extend the Actor class. Which method of Actor do they override?

  2. The ActorScene class has an infinite loop like this:
    while (true)
    {
       for (Actor a : actors)
          a.act()
    }

    In other words, the scene calls the act method on all actors that have been added to the scene, then does it again and again. (Full disclosure: If you look into the run method of ActorScene, the code looks a bit more complex because it runs the act methods in parallel. That way, if you have two robots, they move together. You should not have to worry about that—it just makes the animation more realistic.)

    Actors act in different ways. Read through the code of Robot.act and Beeper.act and describe in plain English how they act.

  3. Make a subclass SquareDancer of Robot with no methods, like this:
    public SquareDancer extends Robot
    {
    }

    What error message do you get?

  4. Look at the Robot class. What constructors does it have?
  5. You need to construct a robot with a starting (x,y) location. Let's do the same for the SquareDancer:
    public SquareDancer extends Robot
    {
       SquareDancer(double x, double y)
       {
       }
    }

    Does the error message go away? If so, why? If not, why not?

  6. You need to pass the x and y values to the Robot constructor. How do you do that? (Hint: super.) Complete the constructor. Your class should now compile.
  7. A square dancer acts like a regular robot, except it makes a quarter turn every four steps, so that it traces out a square:

    Add an instance variable to count the steps. Implement the act method. What is your method?

  8. Change the setup method of MyScene so that you add a SquareDancer instead of a Robot. Compile and run. Attach a screen shot to your lab report.

    Tip: If you add multiple robots to your scene, such as a of Robot and SquareDancer, then

  9. Make a subclass TimidRobot of Robot that acts like a robot, except if a timid robot has moved within 1 unit of an object other than a beeper, it makes a half turn. Position a TimidRobot between two Toaster objects. What is the code for your TimidRobot class?

    Hint: Use the getNeighbors method to get neighbors within one unit, then check whether there is at least one object that is not an instance of a Beeper.

  10. Make a subclass Dino of Actor (not Robot). As you know, dinos love to eat toasters. And they have great vision. In its act method, a Dino first locates the nearest toaster within 10 units and changes its direction towards it. If there is a toaster within 0.5 units, the dino eats it. Otherwise it moves one unit. What is your code for the Dino class? (Follow the Toaster class for guidance how to initialize the model and change to a reasonable size. The model is a Trex If you type Trex and Ctrl+Space, you should get autocompletion for the package and class name in the Alice library.)
  11. Populate your scene with a dozen randomly placed toasters and a couple of dinos. Run it. Attach a screen capture.