Exploring Inheritance

In this lab we will experiment with basic Java inheritance issues while learning to use Eclipse.

  1. First, create a new Java project. Call it, "Lab 1 Inheritance". Second, download four .java files to your machine: Dog.java, Labrador.java, Yorkshire.java, DogTest.java. (Alternatively, download a zip file containing all four: Lab1Dogs.zip.) Find those files in your local file system, select them, and "click and drag" them onto the icon for your new project in the Eclipse's "Package Explorer" window. Eclipse will probably pop up a dialog box asking whether you want to "link" or "copy" the java files. Select "copy". (You may notice that Eclipse has placed a "red X" next to Labrador.java. Don't worry about that for now.
  2. Find and open the directory corresponding to your project (it should be inside a directory with the same name as Eclipse's workspace. You should see copies of the four Java files there now. Place a screen shot of that directory in your lab report. On a Mac, use CMD-CONTROL-SHIFT-4 (the cursor should change to a "plus sign"), then click and drag to select a rectangle of the screen. You should then be able to paste that screen shot into your lab document. (On a Mac, CMD-C and CMD-V are keyboard shortcuts for copy and paste, analagous to CNTL-C and CNTL-V on a PC.)

Before we go any further, here's a brief overview of the java files. Dog.java contains a declaration for a Dog class. Files Labrador.java and Yorkshire.java contain declarations for classes that extend Dog. File DogTest.java contains a simple driver program that creates a dog and makes it "speak".

  1. In Eclipse, open Dog.java and DogTest.java and study them -- notice what instance variables and methods are provided.
  2. Compile and run DogTest (which will implicitly compie Dog, as well) by right-clicking on DogTest.java and selecting Run As: Java Application. Copy the output into your lab document.

 

  1. As you added the Labrador file to your Eclipse project, Eclipse marked the file with a red X, as shown in the image below. Upon opening that file you'll see a red X marking the top of the Labrador constructor. Holding the cursor over the X reveals what message? Place this message into the lab document.eclipse finds an error in Labrador.java
  2. If you look at this line of Labrador.java, the "super constructor" Dog() isn't called anywhere in this file.
    1. What's going on? (Hint: What did we say about constructors in subclasses?)
      Place your answer in the lab document.



    2. Fix the problem (which really is in Labrador) so that DogTest.java creates and makes the Dog, Labrador, and Yorkshire all speak.

  3. Add code to DogTest.java to create both a Labrador and a Yorkshire, and add print statements similar to what exists to have both of them "speak" as well. Make sure the three types of dog "say" different things.

  4. Now add the following method to DogTest.java:
      public static void poke(Dog d) {
        System.out.println(""+d+" says "+d.speak());
    	// System.out.println("and its average weight is "+d.avgBreedWeight());
      }
    
    and add three invocations of poke(), one for each of the dogs, in main(). What output is generated by the three calls to poke? Place this output into the lab document. (By the way, you'll notice that the output has something like, "Dog@236123", or some such. This is generated by the "+d+" code in the println statement. Because the Dog class does not have a toString method, the default is used, which returns the name of the class, appended with the memory address at which the object is stored.)

     

  5. Notice that though there is only one line of code d.speak() (the one in poke()), all three of the speak() methods (one in Dog, one in Labrador, one in Yorkshire) are invoked by the three invocations of poke. Interesting, no? This is an example of polymorphism, a topic we will study in the next chapter. As a further experiment, try removing the comment marks in poke. What error is generated? (Again, just hold the cursor over the red X to see.) Place this output into the lab document.
  6. Next, we'd like to augment poke so that it also prints the "average weight" of each dog. In poke, uncomment the second println line. This will introduce an error, because we haven't yet defined avgBreedWeight.

  7. The easiest way to fix this problem, as you may have guessed, is to add a avgBreedWeight method to Dog. Go ahead and do so, having the method return an integer, representing the weight of the dog in pounds. For now, let's have the method return 5. Run the program. Hopefully everything works.

  8. [Extra Credit] Adding avgBreedWeight to Dog allowed the program to run, but it's not really a satisfactory solution. The problem is that a Dog is a "generic" dog. Because it is generic, it doesn't belong to any particular breed, and hence really shouldn't have an "average breed weight". What we really want to enforce is that every descendant class of Dog should represent a particular breed, and hence every descendant class should be required to provide an averageBreedWeight method. We'll go into this in more detail later, but for now, I'll just indicate what steps you should take:

    Change the int avgBreedWeight() method in the Dog class to be abstract. This means that the word abstract appears in the method header after public, and that the method does not have a body (just a semicolon after the parameter list)--delete the existing body. You'll also have to add the keyword abstract between the "public" and "class" at the top of Dog.java. This specifies that Dog is now an "abstract class". It makes sense for Dog to be "abstract", since Dog has no idea what breed it is. Now any subclass of Dog must have an avgBreedWeight method; because both Yorkshire and Laborador already do, you should be all set on that count.

    Now, though, you should have some new errors. These revolve around the invocation of new in DogTest.java that creates the Dog named "spike". Because Dog is now abstract, it is impossible to create any instances of that class. If you read the error message carefully; it tells you exactly what the problem is. Fix this by changing DogTest (which will mean commenting out some things). Your program should now work just fine. Copy and paste into the lab report a transcript of the execution of your updated DogTest.main().