Section 11.9. Reusing a Class Via Inheritance


[Page 373 (continued)]

11.9. Reusing a Class Via Inheritance

Many children have a hard time with the concepts of left and right. Even some adults get these confused. Let's create a new class ConfusedTurtle that will turn right when asked to turn left and will turn left when asked to turn right. How can we do this?

In Section 11.2.2 we saw that you can specify the parent class when you declare a class using the extends keyword. If you don't specify the parent class the parent class will be Object. So to create a class ConfusedTurtle that is a child of the Turtle class do the following:

public class ConfusedTurtle extends Turtle { }


Because the class ConfusedTurtle inherits from the class Turtle it inherits all its fields and methods. We want to override the method turnLeft() and have it turn right instead. How can we do this? We could just have it call the method turnRight() but we are overriding this method as well. We really want to call the method in the parent class Turtle. Java gives us a way to do this using the keyword super. Usually the Java Virtual Machine (JVM) will start looking for a method in the class that created the current object. But if we use the keyword super to invoke a method, we will start looking for the method in the parent class of the class that created the current object.

public class ConfusedTurtle extends Turtle {   /**    * Method to turn right (but a confused    * turtle will actually turn left)    */    public void turnRight()    {      super.turnLeft();    } 
[Page 374]
/** * Method to turn left (but a confused * turtle will actually turn right) */ public void turnLeft() { super.turnRight(); } }


If we try to compile this we will get an error. The problem is that we haven't created any constructors yet. The compiler will try to add the no-argument constructor for us. But since ConfusedTurtle inherits from Turtle it will also add a call to super() which is a call to the parent's no-argument constructor. It does this to allow initialization of the inherited fields. But, the Turtle class doesn't have a no-argument constructor. Remember that we always passed a World object when we created a new Turtle object (Section 3.4.2).

If we check the Turtle class we don't see a constructor that takes a World object. But there is a constructor that takes a ModelDisplay object. The World class implements the ModelDisplay interface so we can call this constructor and pass in a World object. We need to add a constructor to the ConfusedTurtle class that takes a ModelDisplay object. Then, the first thing we will do is call the parent constructor that takes a ModelDisplay object. To do this we use super(modelDisplayObj). A call to a superclass (parent) constructor must be the first line of code in a constructor. If the compiler doesn't find a call to the parent constructor as the first line of code in a child constructor, it will add a call to the parent's no-argument constructor.

public class ConfusedTurtle extends Turtle {   //////////////// constructors ///////////////////////   /**    * A constructor that takes a ModelDisplay object    * @param modelDisplayObj the thing that does the display    */   public ConfusedTurtle(ModelDisplay modelDisplayObj)   {     // use parent constructor     super(modelDisplayObj);   }   //////////////// methods ///////////////////////////   /**    * Method to turn right (but a confused    * turtle will actually turn left)    */   public void turnRight()   {     super.turnLeft();   } 
[Page 375]
/** * Method to turn left (but a confused * turtle will actually turn right) */ public void turnLeft() { super.turnRight(); } }


To try this out we can do the following:

> World world = new World(); > ConfusedTurtle fred = new ConfusedTurtle(world); > fred.forward(); > fred.turnLeft(); > fred.forward(); > fred.turnRight(); > fred.forward();


Notice that the ConfusedTurtle object still knows how to go forward. The only difference between it and a Turtle object is what happens when it is asked to turn left or right, as shown in Figure 11.17.

Figure 11.17. Result of commands to a confused turtle.


What happens if we also override the turn method in the ConfusedTurtle class to actually turn (360 - the passed degrees)?

/**   * Method to turn by the passed degrees   * (a confused turtle will turn by 360- the   * passed degrees)   */   public void turn(int degrees)   {     super.turn(360-degrees);   }



[Page 376]

We can try this out in the interactions pane with the following:

> World world = new World(); > ConfusedTurtle fred = new ConfusedTurtle(world); > fred.turn(90); > fred.forward(); > fred.turnLeft(); > fred.forward(); > fred.turnRight(); > fred.forward();


If we try this out in the interactions pane we will see that the turn method is doing the right thing but the turnLeft() and turnRight() methods are not (Figure 11.18). What happened? We have to remember that the Java Virtual Machine will always start looking for a method in the class that created the current object (unless we use super.method()).

Figure 11.18. Result of overriding the turn method.


When we call turnLeft() on a ConfusedTurtle object it will invoke the method in the ConfusedTurtle class (Figure 11.19). In that method we call super.turnRight(). This will start looking for the turnRight() method in the Turtle class but not find such a method. Then it will look in the parent class of Turtle, which is SimpleTurtle. The turnRight() method in SimpleTurtle contains this.turn(90); (Figure 11.19).

Figure 11.19. Diagram of the methods executed by fred.turnLeft().
(This item is displayed on page 377 in the print version)


Once again, we will start looking for the turn method in the class that created the current object which was the ConfusedTurtle class (Figure 11.19). The turn(int degrees) method in the ConfusedTurtle class contains the line super.turn(360-degrees);. This will start looking for the turn method in the Turtle class and not find it. It will then look in the parent class of the Turtle class and find it in SimpleTurtle. This will change the heading and redisplay the turtle.

To fix this problem we need to change the turnRight() method in the ConfusedTurtle class to call super.turn(-90) to make it turn left. We will also change the turnLeft() method in the ConfusedTurtle class to call super.turn(90) to make it turn right.


[Page 377]

/**  * Class for a confused turtle. A confused turtle is like  * a turtle but it turns right when asked to turn left and left  * when asked to turn right.  * @author Barb Ericson  */ public class ConfusedTurtle extends Turtle {   //////////////// constructors ///////////////////////   /**    * A constructor that takes a ModelDisplay object    * @param modelDisplayObj the thing that does the display    */   public ConfusedTurtle(ModelDisplay modelDisplayObj)   {     // use parent constructor     super(modelDisplayObj);   }   //////////////// methods ///////////////////////////   /**    * Method to turn right (but a confused    * turtle will actually turn left)    */   public void turnRight() 
[Page 378]
{ // turn left instead super.turn(-90); } /** * Method to turn left (but a confused * turtle will actually turn right) */ public void turnLeft() { // turn right instead super.turn(90); } /** * Method to turn by the passed degrees * (a confused turtle will turn by 360- the * passed degrees) */ public void turn(int degrees) { super.turn(360-degrees); } }


Now if we try this out it should work correctly (Figure 11.20).

> World world = new World(); > ConfusedTurtle fred = new ConfusedTurtle(world); > fred.turn(90); > fred.forward(); > fred.turnLeft(); > fred.forward(); > fred.turnRight(); > fred.forward();


Figure 11.20. Result of fixing the methods turnLeft() and turnRight().
(This item is displayed on page 379 in the print version)


11.9.1. Dynamic (Runtime) Binding

Every object in Java keeps a reference to the class that created it. You can say that an object knows what type it is. When a method is invoked on an object, the Java Virtual Machine (JVM) will always start looking for it in the class that created the object, unless you use super.method(), which will start looking for the method in the parent class of the class that contains the currently executing code.

When you declare a variable you can assign an object to it that is of the declared type, or any child of the declared type. So we can declare a variable of the type Turtle and use it to reference an object of the class ConfusedTurtle. When we invoke a method on a variable, it will first look for that method in the class that created the object that the variable refers to. If we invoke the method turnLeft() on a variable that was declared to be of type Turtle, but was created by the class ConfusedTurtle the method in ConfusedTurtle will be executed. This is due to dynamic or runtime binding. The method that is executed depends on the type of the object when the programming is running, not on the declared type of the variable.


[Page 379]

When we execute the following in the interactions pane, we will get the same result as before (Figure 11.20).

> World world = new World(); > Turtle fred = new ConfusedTurtle(world); > fred.turn(90); > fred.forward(); > fred.turnLeft(); > fred.forward(); > fred.turnRight(); > fred.forward();


Objects always know what type they really are!



Introduction to Computing & Programming Algebra in Java(c) A Multimedia Approach
Introduction to Computing & Programming Algebra in Java(c) A Multimedia Approach
ISBN: N/A
EAN: N/A
Year: 2007
Pages: 191

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net