import java.util.concurrent.ThreadLocalRandom;

/**
 * Illustration of downcasting and class cast exceptions.
 * 
 * @author Drue Coles
 */
public class PetDemo3 {

    public static void main(String[] args) {
        
        // Inheritance expresses an is-a relationship. Wherever a superclass
        // reference is required, a subtype reference is valid. In particular,
        // Dog is assignment compatible with Pet. An upcast is implicit.
        Pet myPet = new Dog("Isaak", 12945); 
        
        if (ThreadLocalRandom.current().nextBoolean()) {
            myPet = new Cat("Muffin"); 
        }    
         
        // If we know that myPet refers to a Dog, we can perform a downcast in
        // order to invoke fetchStick:
        Dog dog = (Dog) myPet; 
        dog.fetchStick(); 
        
        // Late binding enables runtime polymorphism. The appropriate version of
        // the method will be invoked depending on the runtime type of myPet.
        myPet.speak();
    }
}