|
home—info—archive—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
Inheritance: If class B extends A, we say “B is-a A”. Anything a A can do, a B can do too (and possibly more). For example, because Animals can speak, then automatically Dogs can speak.
Note that all fields and methods which are common to all subclasses are actually put inside of the superclass only once. That is, the code for speak and the field sound aren't repeated in each of Cat, Python, Dog, Narwhale, etc..
Mathematically: the set of Bs is a subset of the set of As.
polymorphism:
If a method takes a parameter of type A,
you can actually pass it a B if you want.
For example,
static String threaten( Animal attacker, Animal defender ) { return attacker.speak() + defender.speak() + attacker.speak(); } |
It's a straightforward concept, but it gets the fancy name “polymorphism” because it's the first time that we have an object which is constructed as one type (say, Python), yet declared as another (Animal). We sometimes speak of the object's “underlying type” and its “declared type”.
In fact, with polymorphism, we can have — for the first time — the fact that the “declared” type of a variable might differ from its “actual” type:
Animal a = new Dog( "Fido" ); java.util.List<Dog> pound = new java.util.LinkedList<Dog>(); |
Observe that just because one class extends another, the superclass doesn't have to be abstract; certainly we can make Dogs which aren't some specific sub-class of Dog.
Abstract classes are used to represent “variant types”. (Although they aren't a total solution to this: while Animal does represent Cat-or-Dog-or-Python, you can't make a java type which corresponds to the variants String-or-Dog.)
Example: Suppose we want to sort a list of PizzaServers by salary (ascending). We write some complicated to do so (perhaps after taking ITEC 220); it will involve statements like
List<PizzaServer> sort( List<PizzaServer> employees ) { // ...code, perhaps including loops... Employee itm1 = employees.get(…); Employee itm2 = employees.get(…); if (itm1.getSalary() < itm2.getSalary()) … // ... } |
Then, later, we want to sort a list of Dogs, by age (ascending). This is practically the same problem; the only difference is that this version will involve statements like if (itm1.getAge() < itm2.getAge()) …, (where itm1 and itm2 are now Dogs instead of PizzaServers). Yech! … nearly-repeated-code which is impossible to factor out because one deals with getWeight and another with getAge.
Interfaces, to the rescue! In particular, the the Comparable interface. If both Dogs and PizzaServerss implement the interface, then our sorting code can include
if (itm1.compareTo(itm2) < 0) /* think: "itm1 < itm2" */ … |
class Dog implements Comparable<Dog> { //... other Dog fields/methods public int compareTo( Dog other ) { if (this.getAge() < other.getAge()) { return -1; // Any negative number is good enough to satisfy the interface. } else if (this.getAge() == other.getAge()) { return 0; } else if (this.getAge() > other.getAge()) { return +1; // Any positive number will suffice. } else { System.err.println( "Shouldn't reach this far." ); return 0; // Better than returning a bad answer: Throw an exception. } } } |
In fact, we could sort songs alphabetically-by-artist: we'd have the Song method compareTo which returns a negative number if the artist's name comes alphabetically before the artist of another song. How can we tell if one String is before another, alphabetically? Fortunately, class String implements Comparable itself!
Practice Write compareTo for Songs, so that it compares alphabetically by artist.
Practice
If
class String didn't implement
Comparable,
how would we figure out whether one String comes
before another alphabetically?
Hint: use a loop, and compare individual chars with
>1
Note that we don't want to have these two classes both inherit from some common superclass, each overriding compareTo appropriately. You might argue that perhaps class Object should've had including compareTo in the same way they already included toString and equals. However, there will always be new behaviors which people might want in the future, so having interfaces gives us, as programmers, a power different from abstract classes.
Exercise How do we need to modify class PizzaServer, so that it implements Comparable?
Once a class implements Comparable, we can sort a list of them:
java.util.List<PizzaServer> employees = new java.util.LinkedList<PizzaServer>(); // ... add to the list... employees.toString(); // `sort` is a static method; only compiles if PizzaServer implements Comparable: java.util.Collections.sort( employees ); employees.toString(); |
Another example of interfaces: java.util.List is an interface, which is implemented by LinkedList, as well as a class named ArrayList.2 This means that if we change the signature int numCoversOn( LinkedList<Song> otherSongs ) to int numCoversOn( List<Song> otherSongs ) then our function will be able to handle both LinkedLists, as well as ArrayLists, as well as any other List variant people might invent in the future!
1You can also subtract one char from another, and then compare the result (as an int) to zero. ↩
2 (Its name is a bit confusing; an ArrayList is not an array! It's a List, since it can get(index) and add and answer size() and isEmpty(). That is, it implements the List interface, so therefore an ArrayList is a List. You can't use square-brackets or the field length with ArrayList. It derives its name from the fact that under the hood, it uses arrays to help it organize its contents. But we don't care about how it works, as long as it meets its interface. ↩
home—info—archive—exams—lectures—labs—hws
Recipe—Laws—lies—syntax—java.lang docs—java.util docs
©2008, Ian Barland, Radford University Last modified 2008.Apr.23 (Wed) |
Please mail any suggestions (incl. typos, broken links) to ibarlandradford.edu |