interface Thing { public int age(); } class Animal implements Thing { String name; Animal mom; public int age () { return 0; } public void setName (String givenName) { name = givenName; } public void setMom (Animal myMom) { mom = myMom; } public Animal () { System.err.println("An animal is born."); } public void speak() { System.err.println("I don't know what to do!?"); } public String toString() { return "I'm an animal"; }; } class Dog extends Animal { public Dog () { System.err.println("A dog is born."); } public void speak() { System.err.println("woof"); } public void speakLikeAnAnimal() { super.speak(); } public void fetch() { System.err.println("I'm chasing it as fast as I can!"); } } class Basenji extends Dog { public Basenji () { System.err.println("A basenji is born."); } public void speak() { System.err.println("... (I'm quiet)"); } } class Cat extends Animal { public Cat () { System.err.println("A cat is born"); } public void speak() { System.err.println("meow"); } } public class Animals { public static void main(String[] args) { Thing thing1, thing2; Animal animal1, animal2, animal3, animal4; Animal jacksAnimals[] = new Animal[4]; Animal jillsAnimals[] = new Animal[4]; Dog dog1, dog2; Cat cat1, cat2; Basenji basenji1, basenji2; // basic assignment animal1 = new Animal(); thing1 = new Animal(); dog1 = new Dog(); thing2 = dog1; dog1.setName("fido"); cat1 = new Cat(); cat1.setName("fido"); System.err.println((dog1.name).equals(cat1.name)); System.err.println(dog1.equals(cat1)); basenji1 = new Basenji(); animal2 = new Dog(); dog2 = basenji1; dog2.setMom(dog1); basenji2 = new Basenji(); basenji2.setMom(dog1); System.err.println((basenji2.mom).equals(dog2.mom)); System.err.println(dog2); jacksAnimals[0] = animal1; jacksAnimals[1] = dog1; jacksAnimals[2] = cat1; jacksAnimals[3] = basenji1; for (int i=0; i<4; i++) { jillsAnimals[i] = jacksAnimals[i]; } System.err.println(jillsAnimals.equals(jacksAnimals)); System.err.println("Method invocation:"); System.err.println("\nWith specific types:"); animal1.speak(); dog1.speak(); cat1.speak(); basenji1.speak(); System.err.println("\nWith widening:"); animal2.speak(); dog2.speak(); System.err.println("\nWith array of animal type:"); for (int i = 0; i < 4; i++) { jacksAnimals[i].speak(); } System.err.println(); dog1.fetch(); // jillsAnimals[1] happens to be a dog, but this yields compilation error // jillsAnimals[1].fetch(); // okay at compile and run time ((Dog)jacksAnimals[1]).fetch(); // okay at compile time, but run-time error since jacksAnimals[2] contains a cat //((Dog)jacksAnimals[2]).fetch(); // Narrowing Assignments //System.err.println("\nNarrowing assignments:"); //dog2 = animal1; //dog2 = animal2; // narrowing, with animal2 = a Dog, and a cast cat2 = (Cat) jacksAnimals[2]; //dog2.speak(); // allowed? //cat2 = (Cat)((Animal)cat1); } }