/**	This class demonstrates the concept of inheritance. The main
 *	class creates various objects from an inheritance hierarchy,
 *	then calls inherited and overridden methods.
 *
 *	@author Steven J. Castellucci
 *	@version 1.0 - (10/2008)
 *	COPYRIGHT (C) 2008 All Rights Reserved.
 */
public class InheritanceExample
{
	public static void main(String[] args)
	{
		// Output the example inheritance hierarchy.
		System.out.println("");
		System.out.println("Inheritance hierarchy:");
		System.out.println("   Shape");
		System.out.println("   |- Rectangle");
		System.out.println("      |- Square");
		System.out.println("");
		System.out.println("");

		// Create objects of type Shape and its subclasses.
		Shape s1 = new Shape();
		Shape s2 = new Rectangle();
		Shape s3 = new Square();
		System.out.println("Shape s1 = new Shape();");
		System.out.println("Shape s2 = new Rectangle();");
		System.out.println("Shape s3 = new Square();");
		System.out.println("");
		System.out.println("");

		// Output tests of each object.
		System.out.println("Shape s1:");
		System.out.println("instanceof Shape     -> " + (s1 instanceof Shape));
		System.out.println("instanceof Rectangle -> " + (s1 instanceof Rectangle));
		System.out.println("instanceof Square    -> " + (s1 instanceof Square));
		System.out.println("inheritedMethod() output:");
		s1.inheritedMethod();
		System.out.println("overriddenMethod() output:");
		s1.overriddenMethod();
		System.out.println();
		System.out.println("");

		System.out.println("Shape s2:");
		System.out.println("instanceof Shape     -> " + (s2 instanceof Shape));
		System.out.println("instanceof Rectangle -> " + (s2 instanceof Rectangle));
		System.out.println("instanceof Square    -> " + (s2 instanceof Square));
		System.out.println("inheritedMethod() output:");
		s2.inheritedMethod();
		System.out.println("overriddenMethod() output:");
		s2.overriddenMethod();
		System.out.println();
		System.out.println("");

		System.out.println("Shape s3:");
		System.out.println("instanceof Shape     -> " + (s3 instanceof Shape));
		System.out.println("instanceof Rectangle -> " + (s3 instanceof Rectangle));
		System.out.println("instanceof Square    -> " + (s3 instanceof Square));
		System.out.println("inheritedMethod() output:");
		s3.inheritedMethod();
		System.out.println("overriddenMethod() output:");
		s3.overriddenMethod();
		System.out.println();
		System.out.println("");
	}
}


/**	This class will represent the root of the example
 *	inheritance hierarchy. */
class Shape
{
	/**	All subclasses will have access to this method. */
	public void inheritedMethod()
	{
		System.out.println("   This shape has volume.");
	}

	/**	All subclasses will have access to this method too,
	 *	but they will override it. */
	public void overriddenMethod()
	{
		System.out.println("   This shape is a... shape :-)");
	}
}


/**	This class inherits from Shape -- it is a subclass of it. */
class Rectangle extends Shape
{
	/**	This class overrides Shape's overriddenMethod() method. */
	public void overriddenMethod()
	{
		System.out.println("   This shape is a rectangle.");
	}
}


/**	This class inherits from Shape and Rectangle -- it is a
 *	subclass of both. */
class Square extends Rectangle
{
	/**	This class overrides Rectangle's overriddenMethod()
	 *	method, but also calls it using the keyword "super". */
	public void overriddenMethod()
	{
		super.overriddenMethod();
		System.out.println("   ...but it is also a square.");
	}
}
