Chapter 8


Exercise 1 Which of the following hierarchies illustrate a good understanding of the difference between classes and objects? Which ones represent mistaken understanding? The arrows mean "has subclass", so in option A, Shape Triangle means "class Shape has subclass Triangle."

  1. Shape Triangle RightTriangle

  2. GreatLiterature GreatPoem DivineComedy

  3. Planet Continent

  4. Person HeadOfState Emperor

  5. Person HeadOfState Emperor AugustusCaesar

Solution 1 A and D are good examples. "RightTriangle" is a category that falls within the broader category of "Triangle", which falls within the even broader category of "Shape". Similarly, "Emperor" is a category that falls within the broader category of "HeadOfState", which falls within the even broader category of "Person".

B starts off well: "GreatPoem" is a category that falls within the broader category of "GreatLiterature". But Dante's Divine Comedy is not a category. It is an instance of a category. In software, divineComedy should be an instance of class GreatPoem, which would be a subclass of GreatLiterature.

C isn't even close. Certainly, planets contain continents, and both planets and continents are categories of things, but a continent is not a more specific kind of planet. It would not be appropriate for class Continent to extend class Planet. (It might be appropriate for the two classes to exist, but be unrelated in terms of inheritance. In this case, perhaps Continent would have an array of Planet.)

E is like B. The last item is an instance of a category, not a category. Emperor is a category, but there was only one Augustus Caesar. So AugustusCaesar could be an instance of class Emperor, which extends class HeadOfState, which extends class Person.

Exercise 2 Which of the following classes have a no-args constructor?

  1. A)

    class A { }
  2. B)

    class B {   B() { } }
  3. C)

    class C {   C(int x) { } }
  4. D)

    class D {   D(int y) { }   D() { } }

Solution 2 There are two ways for a class to get a no-args constructor:

  • It can define one explicitly.

  • It can define no constructors at all. In that case, the compiler provides a default no-args constructor.

A has no constructors, so it is given a default no-args constructor. B and D define their own no-args constructors. C defines a constructor that takes arguments, so it has no no-args constructor.

Exercise 3 Write the code for two classes. The first, called WaterBird, has a float variable called weight. The class has a single constructor that looks like this:

WaterBird(float w) {   weight = w; }

Compile this class. Now create the second class, called Duck, which extends WaterBird. Duck has no variables or methods, so it shouldn't take you long to write it. Will Duck compile? First, think about the issues involved. Then try to compile Duck and see if you were right.

Solution 3 The Duck class looks like this:

public class Duck extends WaterBird { }

It looks innocent enough, but if you've watched enough cartoons, you know that innocent-looking ducks are not to be trusted. This class defines no constructors, so it gets a default no-args constructor that does almost nothing. The constructor doesn't initialize anything (since it contains no code), but it does participate in the chain of construction. Thus, it tries to call the superclass's default constructor, and there we get into trouble.

The WaterBird superclass defines a constructor that takes an argument. There is no explicit no-args constructor, and there is no automatic default constructor. So an invisible piece of functionality in an invisible constructor in Duck is trying to call something in WaterBird that does not exist. When you try to compile Duck, you get an error message. The text of the message may vary depending on your compiler, but it will say something like this:

Constructor WaterBird() not found in class WaterBird

This kind of trouble is called the constructor trap. To get out of the trap, add a no-args constructor to the superclass.

Exercise 4 Write some code to demonstrate to yourself the chain of construction. Create an inheritance hierarchy of 4 classes. Give them any names you like. They don't have to have any data or methods, but each one should have a no-args constructor. These constructors should print out a line identifying the current class (something like "Constructing an instance of WaterBird"). Your main() method should construct a single instance of your lowest-level subclass. What is the output? Does it matter which class contains the main() method?

Solution 4 Here is one solution:

public class TwoDShape {   TwoDShape()   {     System.out.println("Constructor for TwoDShape");   } } public class Polygon extends TwoDShape {   Polygon()   {     System.out.println("Constructor for Polygon");   } } public class Triangle extends Polygon {   Triangle()   {     System.out.println("Constructor for Triangle");   } } public class RightTriangle extends Triangle {   RightTriangle()   {     System.out.println("Constructor for RightTriangle");   }   public static void main(String[] args)   {     new RightTriangle();   } }

The output is

Constructor for TwoDShape Constructor for Polygon Constructor for Triangle Constructor for RightTriangle

The application's behavior and output are the same no matter which class owns the main() method. However, it seems cleaner to put main() in RightTriangle. Anyone who reads the code for the first time will see the call to the RightTriangle constructor and wonder what class RightTriangle looks like. That person's job is easier if the RightTriangle class is the one they are already looking at.

In general, in a multiclass application you have some choices as to where to put your main() method. As always, think about which choice will be the clearest to someone reading the code for the first time.

Exercise 5 Write some code to demonstrate inheritance polymorphism. Create a superclass class with 3 subclasses. The superclass should have a method that prints out a line identifying the current class (something like "I am a Monster"). Two of the subclasses should override this method to print out a different message (like "I am a Werewolf"). Give the superclass a main() method with an array of size 4, typed as the superclass (for example, Monster[] monsters = new Monster[4];). Your main() should populate the array with references to 4 objects, each with a different class, and then traverse the array, calling your method on each array component. What is the output? Does it matter which class contains the main() method?

Solution 5 Here is one solution:

public class Monster {   void identify()   {     System.out.println("I am a monster.");   }   public static void main(String[] args)   {     Monster[] monsters = new Monster[4];     monsters[0] = new Monster();     monsters[1] = new Dragon();     monsters[2] = new Werewolf();     monsters[3] = new Cyclops();     for (int i=0; i<monsters.length; i++)       monsters[i].identify();   } } public class Dragon extends Monster {   void identify()   {     System.out.println("I am a dragon.");   } } public class Werewolf extends Monster {   void identify()   {     System.out.println("I am a werewolf.");   } } public class Cyclops extends Monster {   void identify()   {     System.out.println("I am a cyclops.");   } } 

The output is

I am a monster. I am a dragon. I am a werewolf. I am a cyclops.

Again, programmatically it doesn't matter which class gets the main() method. As for readability, the major piece of data in main() is an array of Monster, so it makes sense to put main() in Monster.




Ground-Up Java
Ground-Up Java
ISBN: 0782141900
EAN: 2147483647
Year: 2005
Pages: 157
Authors: Philip Heller

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