CS51 - Spring 2010 - Lecture 15

  • midterm
       - average 84

  • administrative
       - keep doing the practice problems
       - no lab this week (Friday is a holiday)

  • show FallingLeaves demo
       - we saw this before
       - how does it work?
          - we have a tree that is an ActiveObject, that generates some number of leaves, which are also ActiveObjects
          - Tree class randomly picks between the two different leaf options
          - each time we click, we create a new Tree

  • review FallingLeaves code

  • show FallingObjects demo
       - We now have not only falling leaves, but also falling hail
       - How would we modify the code?
          - we could try and modify the FallingLeaves class to support the addition of the hail
             - this would make the code much more complicated
             - would not be good object oriented design
          - a better way is to add a new Hail class
             - create the Hail class
             - change the Tree class to have another random option
             - the hail class would look very similar to the FallingLeaf class except with FilledOval instead of a VisibleImage
                - if you ever find yourself doing a lot of copy and pasting when programming, there's probably a better way to do it!

  • inheritance
       - Java has what's call class inheritance
       - for a class to "inherit" from another class, we use the keyword "extends"
       - where have we seen this so far?
          - extends WindowController
          - extends ActiveObject
       - when a class "extends" another class, it inherits the attributes and behaviors from the parent class
          - the extending class is called the subclass
          - the parent class (being extended) is called the superclass
          - the subclass inherits all of the attributes from the parent class, that is all of the non-private methods and variables
             - private methods are only visible within a class
             - this is where the "canvas" variable comes from, we inherit it
       - we've seen public and private scopes for variables and methods, for inheritance, we need one more: protected
          - why do we need another scoping classification?
             - private is only visible within the class
             - public is visible to everyone
          - protected gives us a middle ground, where they're not visible to everyone, but are visible to subclasses

  • a simple inheritance example

    public class Ball{
       public Ball(){
          // some code
       }   

       public bounce(){
          // some code
       }

       public setSize(double d){
          // some code
       }

    }

    public class BasketBall extends Ball{
       public BasketBall(){
          // some code
       }

       public shoot(){
          // some code
       }
    }
       
       - Say we declare a new object of type BasketBall:
          BasketBall bball = new BasketBall()

       - all of the following would be appropriate:
          - bball.shoot()
          - bball.bounce()
          - bball.setSize(10)

  • how can we use inheritance to help us in our hail/leaf example?
       - look at FallingObject class in FallingObjects code
          - represents a generic falling object
             - we use the Drawable2DInterface to allow it the falling object to be a variety of different things
             - note that it is protected, why?
                - subclasses will need to define the actual object, i.e. with a "new" statement
          - constructor just specifies the speed and the stopping height
          - run method
             - moves the object down the screen and then removes it when it gets to the bottom
          - notice that this class does NOT define "object"
             - what would happen if we created a new FallingObject?
                - we'd get a null pointer exception
       - how does this class help us then?
          - we can inherit from this class!
       - look at FallingLeaf class
          - extends FallingObject
          - the "super" keyword allows us to call the constructor of the parent, superclass
             - must be the first line in the constructor
          - create a new VisibleImage and associate it with the "object" variable that we inherited from FallingObject
          - where is the run method?
             - we don't need one... we inherit it from the FallingObject class
       - what will the Hail class look like?
          - extends FallingObject
          - create a new FilledOval for object (rather than a VisibleImage)

  • benefits of inheritance
       - saves us from having to write code multiple times
       - makes shared behavior explicit
       - has the code in one place in case we decide to change it

  • show FallingObjectsWithTomatoRun demo
       - what do we need to change?
          - add a Tomato class that extends FallingObject
       - can we simply extend FallingObject and use the generic run method?
          - the run method in FallingObject removes the object from the canvas when it reaches the bottom
          - we want do want to remove the object, but also want to create a "splat" where the tomato lands
       - in the run method for Tomato:
          - do the normal FallingObject run
          - then create a new red FilleOval at the bottom for the splat
       - look at Tomato class in FallingObjectsWithTomatoRun code
          - constructor is as we'd expect
          - the run method is what is called "overridden"
             - when the subclass defines a method with the same name and parameters, the method is overridden
                - instead of calling the parents method, it will call the classes method
          - often, when we override a method, we just want to alter the behavior of the method
             - super.run() calls the run method of the superclass
             - in general, super.methodName(), will call methodName of the super class
          - what does the run method do?
             - calls the run method of the superclass (i.e. FallingObject)
                - this will cause the original red, FilledOval to fall and then be removed when it reaches the bottom
             - create the splat

  • show FallingObjectsWithCows demo
       - we've added a two more classes
          - Cow (representing the Williams mascot, which is named Ephelia)
          - Cecil (representing the Pomona mascot)
       - how are these new classes related to the Tomato class?
          - like the tomato class, their run method has two stages:
             - fall down the screen
             - do something when they hit the bottom
       - how can we implement these?
          - we could do the same thing we did for the Tomato class...
          - better way is to add a hitBottom method in the FallingObject class

  • look at FallingObjectsWithCows code
       - look at the FallingObject class
          - we've made an explicit method called hitBottom that simply removes the object from the canvas
          - how does this help us?
             - classes that extend this class can override that method
          - why is it protected?
             - if we made it private, then we couldn't override it
       - what will the Cecil and Cow classes look like?
          - like the others, in the constructor, create a new VisibleImage, etc.
          - will only have to override the hitBottom method to change the functionality!
          - don't need to override the run method

  • draw the hierarchy tree for these classes

  • classes can only extend one class. Why?
       - avoid ambiguity
          - what if you inherited from two classes that both defined the same method? Which one would be called?

  • inheritance and types
       - which assignment statements do you think are legal?
          Cow c;
          FallingObject f;

          c = new FallingObject(...);
          f = new Cow(...);

          c = f;
          f = c;

       - you can use a subclass anywhere you could use the superclass, but NOT vice versa, why?
          - In the example above, we know that the cow has at least all of the functionality of a FallingObject, so anywhere we could use a FallingObject, we would use a Cow. The reverse is not true.
       - must be able to be figure it out from ONLY looking at that exact statement (i.e. not the history)
          FallingObject f = new Cow(...);

          Cow c = f; // would not be a valid statement!

          - if you know it's true, you can typecast it:
             Cow c = (Cow)f; // now it's valid

       - the "instanceof" command allows you to ask the boolean question of whether an object is of the specified type
          FallingObject f = new Cow(...);
          FallingObject f2 = new FallingObject(...);

          System.out.println(f instanceof Cow);
             - true
          System.out.println(f instanceof FallingObject);
             - true
          System.out.println(f2 instanceof Cow);
             - false
          System.out.println(f2 instanceof FallingObject);
             - true