You know how to define objects. You understand static and non-static members. You also understand constructors. You usually want to model something; you enumerate the features you're interested in that thing and then you define a class that has instance members (variables and methods) in its blueprint so you can create objects of that type by invoking the new operator on that class. We're focused on modeling. We model by defining classes. The blueprint in a class (that holds the instance members) supports that modeling business. You don't have to model in one step. You can do it in stages. You can use the class extension mechanism which leads to inheritance, polymorphism and dynamic method lookup. The class extension mechanism is our topic for today. The trouble is not that this is hard. It's that it opens to door to everything else. EVERYTHING ELSE. class Horse { void talk() { System.out.println("Howdy."); } } class Story { public static void main(String[] args) { Horse a = new Horse(); a.talk(); } } -------------------------- class Horse { void talk() { System.out.println("Howdy."); } } class Story { public static void main(String[] args) { Horse a = new Horse(); a.talk(); Unicorn b = new Unicorn(); b.poke(); b.talk(); // inheritance Horse c = new Unicorn(); // polymorphism // c.poke(); // not possible any longer c.talk(); } } class Unicorn extends Horse { void poke() { System.out.println("I am poking..."); } } ---------------------------- Summary so far: the class extension mechanism is like the set union of features. Horse = {talk()}, Unicorn = Horse U {poke()}. This is very easy. The only problem is when the extending class defines members with the same name as in the super-class. In that case we might have something like Horse = { talk() } and Unicorn = = Horse U { talk() } so now we have a multiset. {a} U {b , c} = {a, b, c} {a, b} U {a, c} = {a, b, c} which is is the a in the answer? Or is it really {a, a, b, c} or even {a, b, a, c}? class Horse { void talk() { System.out.println("Howdy."); } } class Story { public static void main(String[] args) { Horse a = new Horse(); a.talk(); Unicorn b = new Unicorn(); b.talk(); // perhaps Bonjour will come out System.out.println("-------------------------"); Horse c = new Unicorn(); // polymorphism c.talk(); // hard to anticipate: what is the convention // first you ask yourself: can c talk? It's a Horse. Yes. // then you follow c to the object and determine its type; // c takes you to an object of type Unicorn. Once you do // that you invoke the talk from the object's class: Unicorn. // So if there is no talk in Unicorn we get Howdy, otherwise // we get the French greeting: Bonjour. } } class Unicorn extends Horse { void talk() { System.out.println("Bonjour"); } } -------------------------------------------- class Horse { void talk() { System.out.println("Howdy."); } } class Story { public static void main(String[] args) { Horse c = new Unicorn(); c.talk(); } } class Unicorn extends Horse { void talk() { super.talk(); System.out.println("Bonjour"); } } So that's dynamic method lookup and now let's examples of it in action. Horse a = new Horse() or Horse a = new Unicorn(). In both cases I can say: a.talk() the dynamic aspect of it is that it's OK to ask for talk but the type of the object you're pointing to (with a) determines which method runs. /* */ import java.applet.*; import java.awt.*; public class Unicorn extends Applet { int i = 0; public void paint(Graphics g) { i = i + 1; System.out.println("I am painting for the " + i + "th time."); } } -------------------------------------------------------- /* */ import java.applet.*; import java.awt.*; public class Unicorn extends Applet { int size = 20; Circle[] circles; public void init() { circles = new Circle[size]; for (int i = 0; i < size; i++) { circles[i] = new Circle( (int) (Math.random() * 200 + 100), (int) (Math.random() * 200 + 100), (int) (Math.random() * 20 + 20), new Color( (float) Math.random(), (float) Math.random(), (float) Math.random()) ); } } public void paint(Graphics g) { for (int i = 0; i < circles.length; i++) circles[i].draw(g); } } class Circle { int x, y, radius; Color c; Circle(int x, int y, int radius, Color c) { this.x = x; this.y = y; this.radius = radius; this.c = c; } void draw(Graphics g) { g.setColor(c); g.fillOval(x, y, 2 * radius, 2 * radius); g.setColor(Color.black); g.drawOval(x, y, 2 * radius, 2 * radius); } }