Inheritance and Polymorphism I

Let me just reiterate that this is probably the hardest topic in the course to really wrap your head around---so if it seems confusing, don't worry too much.  These notes cover everything we discussed this week, plus a bit more.  Do your best with what's here and we'll pick up with some practice problems in the next section.

See also: Lecture Notes for this topic (10/7).
 
 Binding
Binding is the process Java uses to connect a method name with the actual code that implements it, or a variable name with the particular memory slot that contains it---which is tricky when several methods or variables have the same name.  Binding starts searching for a method or variable at a specific starting class.  Then it looks for the version of the item that is most specific to that class.  (So if the starting class does not contain a version, it will go to the most immediate parent class that does contain one).

Static Binding 
Looks at type of the reference (the variable); assumes object pointed to is of this class.  This binding is predetermined at compile time, since the type of a variable never changes.

Dynamic Binding 
Looks at type of actual object being pointed to.  Since this binding depends on the value of the variable (what it is pointing to), this binding must happen while the program is running (hence, "dynamic").

Note that some version of the method or variable still has to be accessible via plain static binding.  This guarantees that when dynamic binding happens at runtime, there will always be something to find.  So a variable can never point to an object whose class doesn't have any version of the item in question.

Comparison
 
Static binding Dynamic binding
Name conflicts are called Shadowing Overriding
How resolved Looks at type of reference Looks at type of object being pointed at
Used for - data members
- private methods*
- static methods
- all other methods
* This is true even if using dynamic binding you could find a more specific, but still accessible version (a public version in a subtype)

 Interfaces
  Because of dynamic binding, it's ok to have a variable where the reference type is an interface.  Since it is impossible to instantiate an object that is actually of that type, we know the reference will instead always be pointing to an object of a type that implements the interface.  Dynamic binding will be used based on this object's type.  Notice how all items that do use static binding cannot be placed in interfaces--think about why it would be a problem if they could be... 

Interfaces can extend other interfaces.  Classes can only implement interfaces; they cannot extend them. 
 

 Casting
  Casting is the process of changing from one reference type to another.  The type of the object being pointed to is not changed.  In fact, nothing about the object being pointed to changes, and nothing about the original pointer itself changes.  Casting gives you a new pointer, of a different type, to the same object.

Upcasting - Casting from a child type to its parent type--more general.
Downcasting - Casting from a parent type to a particular child type--more specific.
One way to remember: think of an aerial view.  Moving up gives you a broader view, moving down gives you more specifics.

  • Upcasting is implicit--Java will do the cast automatically if you don't write it.
  • Upcasting is guaranteed to work (if you are pointing to a child type, you know the object is also of the parent type).
  • Downcasting is explicit--you need to write a cast expression or else Java will throw a fit when you compile.
  • Downcasting is not guaranteed to work:
    • If your pointer is of the parent type, it may or may not be pointing to an object of the child type you want.  This depends on the value of the reference variable, which of course is not known until run time.
    • At runtime, if the actual type of the pointed-to object matches or is a subclass of the type you are trying to cast to, the cast succeeds.
    • If it is not, you get a ClassCastException.
  • It's possible to write a cast that is guaranteed to fail, by casting from one type to another that is neither a parent nor child of the first type (e.g., String->Integer).  Java considers there casts invalid and won't compile them.
  • Casting can go several "steps" at a time--so you could try to cast from a parent type to one of its children's children, for example.
Syntax 
An explicit cast looks like:
  (type to cast to)reference 
  Example: intPuzzle = (PuzzleAsInt)somePuzzle 

Becuase of Java's "order of operators" (precedence), you will often need to add extra parentheses:
  ( (type to cast to)(reference) ).member 
 

Peter Flynn