Runtime polymorphism
| Code | final Object[] instances = {
  new String("Test"),
  new Date()
};
printMetaInfo(instances);
-----------------------------------------------------    
static void printMetaInfo(Object[] objects) {
  for (Object o: objects) {
    System.out.println(o.getClass().getName());
  }
} | 
                                   
                        
|---|---|
| Result | java.lang.String java.util.Date  | 
                                   
                        
 | 
                                   
                        |
 | 
                           
                                     
                            | 
                                   
                        
| Code | final Shape[] shapes = {
  new Rectangle(0, 0, 2, 3),
  new Circle(0, 0, 1)};
}
printAreas(shapes);
----------------------------------------
static void printAreas(Shape[] shapes) {
  for (Shape shape : shapes) {
    System.out.println(shape.getArea());
  }
} | 
                                   
                        
|---|---|
| Result | Area:6.0 Area:3.141592653589793  | 
                                   
                        
public abstract class Shape {
...
public final double getArea(){
  if (this instanceof Rectangle rectangle) {
    return rectangle.width * rectangle.height;
  } else if (this instanceof Circle circle) {
    return circle.radius * circle.radius * Math.PI;
  } else {
    return 0; // Unreachable
  }
} | 
                           
                  |
public class Rectangle extends Shape { ... protected int width, height; }  | 
                     
                             
                     public class Circle extends Shape { ... protected int radius; }  | 
                           
                  
