import java.util.Arrays; 

class Seth {
  public static void main(String[] args) {
    Circle a = new Circle(); 
    Rectangle b = new Rectangle(); 
    Circle c = new Circle(); 
    Object[] shapes = new Object[3]; 
    shapes[0] = a; // polymorphism
    shapes[1] = b; 
    shapes[2] = c; 
    
    System.out.println( a.area() ); 
    System.out.println( b.area() ); 
    System.out.println( c.area() ); 
    
    for (Object o : shapes)
      System.out.println( o.area() ); 
       
  }
}

class Circle {
  public String toString() {
    return "Soy un círculo.";  
  }
  public double area() {
    return Math.PI;  
  }
}

class Rectangle {
  public String toString() {
    return "Ik ben een rechthoek";  
  }
  public double area() {
    return Math.E;  
  }
}

Can we make this work? What do we need? 

interface Shape {
  public double area();  
}

class Circle implements Shape {
  public String toString() {
    return "Soy un círculo.";  
  }
  public double area() {
    return Math.PI;  
  }
}

class Rectangle implements Shape {
  public String toString() {
    return "Ik ben een rechthoek";  
  }
  public double area() {
    return Math.E;  
  }
}

class Seth {
  public static void main(String[] args) {
    Circle a = new Circle(); 
    Rectangle b = new Rectangle(); 
    Circle c = new Circle(); 
    // Object[] shapes = new Object[3]; 
    Shape[] shapes = new Shape[3]; 
    shapes[0] = a; // polymorphism
    shapes[1] = b; 
    shapes[2] = c; 
    
    // for (Object o : shapes)
    for (Shape o : shapes) 
      System.out.println( o.area() ); 
       
  }
}

What is an abstract class? 

public abstract class Shape {
  public abstract double area();  
}

class Circle extends Shape {
  public String toString() {
    return "Soy un círculo.";  
  }
  public double area() {
    return Math.PI;  
  }
}

class Rectangle extends Shape {
  public String toString() {
    return "Ik ben een rechthoek";  
  }
  public double area() {
    return Math.E;  
  }
}

And Seth.java is unchanged. 

class Seth {
  public static void main(String[] args) {
    Circle a = new Circle(); 
    Rectangle b = new Rectangle(); 
    Circle c = new Circle(); 
    // Object[] shapes = new Object[3]; 
    Shape[] shapes = new Shape[3]; 
    shapes[0] = a; // polymorphism
    shapes[1] = b; 
    shapes[2] = c; 
    
    // for (Object o : shapes)
    for (Shape o : shapes) 
      System.out.println( o.area() ); 
       
  }
}

Now what else can an abstract class do that an interface can't?

Answer: I can place instance variables in a class (abstract or not). 

An abstract class can have a constructor.

An abstract class cannot be instantiated directly. 

The apparent contradiction is resolved by constructor chaining. 

class Horse {
   String name; 
   public String toString() {
     return "Hi I'm a Horse, my name is " + this.name;  
   }
}

This is how it runs: 

Welcome to DrJava.  Working directory is C:\Users\dgerman\Desktop
> Horse a = new Horse();
> a.name
null
> a
Hi I'm a Horse, my name is null
> a.name = "Toby";
> a
Hi I'm a Horse, my name is Toby


I add a class like yesterday

class Unicorn extends Horse {
  public String toString() {
    return "I am a Unicorn named " + this.name; 
  }
}

This runs as follows: 

Welcome to DrJava.  Working directory is C:\Users\dgerman\Desktop
> Unicorn a = new Unicorn();
> a.name
null
> a
I am a Unicorn named null
> a.name = "Misty"
"Misty"
> a
I am a Unicorn named Misty


Now what? 

class Horse {
  String name; 
  Horse(String name) {
    this.name = name;  
  }
  public String toString() {
     return "Hi I'm a Horse, my name is " + this.name;  
   }
}

class Unicorn extends Horse {
  public String toString() {
    return "I am a Unicorn named " + this.name; 
  }
}

The code above works fine until I define a constructor in Horse. 

--

Constructor Chaining

Rule 1. If you have no constructor Java will give you a default 
no-arg constructor. So if I have this 

class One {

}

It means I have this

class One {
  One() {

  }
}

Rule 2. If you define at least one constructor you are no longer in
default so you have only what you defined. In other words if you have

class One {
  One (int n) {

  }
}

Now you can do this: One a = new One() any longer!

Rule 3. Every time a constructor of a class is invoked the superclass
constructor is invoked first. Which constructor in the superclass will
be invoked, if you have more? Answer: whichever you specify. What if 
there is no constructor in the superclass? In that case by Rule 1 we 
do have a no-arg default constructor there so hopefully that one will
invoked. What if you don't have a constructor defined in your class? 

class One {
  
}

class Two extends One { 

}

The second case now becomes (refinement of Rule 1):

class Two extends One { 
  Two() {
    super(); 

  } 
}

I'm going to post all the rules and a set of exercises for tomorrow. 

My code now looks as follows: 

class Horse {
  String name; 
  Horse(String name) {
    this.name = name;  
  }
  public String toString() {
     return "Hi I'm a Horse, my name is " + this.name;  
   }
}

class Unicorn extends Horse {
  Unicorn(String name) {
    super(name); // respects constructor chaining 
  }
  public String toString() {
    return "I am a Unicorn named " + this.name; 
  }
}

This runs like this: 

Welcome to DrJava.  Working directory is C:\Users\dgerman\Desktop
> Unicorn a = new Unicorn("Misty");
> a
I am a Unicorn named Misty
> Horse b = new Horse("Toby"); 
> b
Hi I'm a Horse, my name is Toby


--