//
// file: ObjectRefsConversion.java
// demonstrate object reference conversion and casting
// For demo purposes and an easy download everything
// is contained in this file : 6 classes and
// one interface
// 	ObjectRefsConversion (main)
// 	Fish
// 	Trout
// 	Speckled
// 	Rainbow
// 	Brown
// 	Edible (interface)
//
// ObjectRefsConversion is the public class
// The classes are empty shells since this is demo of
// conversion and casting

class ObjectRefsConversion {	

	public static void main(String args[]) {
		Speckled sRef = new Speckled();		

/*          * Case: NewType and OldType are both classes		 
            * OldType must be subclass of NewType
            * Convert "up" the hierarchy
            * We CAN convert a Speckled to a Trout because
            * a Speckled "is a" Trout
*/		

		Trout tRef = sRef;
		System.out.println("tRef is of type:"+tRef.toString());		

		// Consider		
		//		sRef = tRef;		
		// Compiler complains with :		
		// "Explicit cast needed to convert Trout		
		//  to Speckled "		
		// We CANNOT convert a Trout to a Speckled		

/*		* Case : NewType is an interface, OldType is a class
      	* OldType must implement the interface		 
		* Case : NewType is class, OldType is an interface		 
		* NewType must be an java.lang.Object		 
		* (This is rather obscure)		 
*/
		Edible ed = tRef;
		java.lang.Object newInterface = ed;		

/*		* Case : NewType is an class, OldType is an array		 
		* NewType must be java.lang.Object		 
		* array "is an" Object
		* (Also obscure)
		* Case : NewType is an array, OldType is a class
		* Compiler Error : An array but be converted to
		* a class, but a class may not be converted to
		* an array
*/

		Trout tArray[] = new Trout[10];		 
		java.lang.Object newArray = tArray;		 
		System.out.println("newArray is: "+newArray.getClass());		 
		if(newArray.getClass().isArray()) {		 	
			System.out.println("newArray is an array.");			

/*		* but below does not work, although it's tempting			 
		* for(int i=0;i<newArray.length;i++)
		* newArray[i] = new Trout();
*/

		}		 

		// Attempts to convert an array to any class type		 
		// other than Object results in a Compiler error		 
		//		 
		// tRef = tArray;		 
		// "Can't convert Trout to Trout[]"		

/*		* Case : NewType is an Array, OldType is an Array		 
		* OldType must be of an array of Object Reference		 
		* Types that can be converted to NewType		 
		*		 
		* Below works because sArray[] can be converted
		* to tArray because a Speckled "is a" Trout
*/		 

		Speckled[] sArray = new Speckled[10];		 
		tArray = sArray;		 

		// Compiler Error		 
		// Can't convert Trout[] to Speckled[] because		 
		// can't convert Trout to Speckled		 
		// sArray = tArray;		

/*		* OBJECT REFERENCE CASTING		 */		

		Speckled s, s1;		
		Trout t;		
		Brown b;		
		s = new Speckled();		

		// Assignment Conversion		

		t = s;		

/*		* Case : OldType,NewType are classes		 
		* Compile Time Check; One class must be a subclass		 
		* of the other		 
		*		 
		* s1 is declared as type Speckled. t is declared as type
		* Trout. Since Speckled is a subclass of Trout compile time		 
		* checks are satisfied		 
		*		 
		* b is type Brown, t is declared as type Trout		 
		* At compile time this is a perfectly legal cast,		 
		* one class is a subclass of the other		 
		*		 
		* However ....		 
		* The compiler cannot determine the type of object that		 
		* every reference will "refer to" at run time		 
		* t contains a reference to Speckled from the Assignment		 
		* conversion above		 
		* The first cast below is fine. The second cast attempts		 
		* to convert a Speckled to a Brown. This fails the		 
		* "is a" test.		 
*/		

		s1 = (Speckled)t; 	// legal cast Speckled to Speckled		
		// b = (Brown)t;
		// Run Time Exception, can't convert						// Speckled to Brown	
	}
} //ObjectRefsConversion

interface Edible {	
	public void eat();
}

abstract class Fish {	
	private String classID = "Class Fish";
	public String toString() { return classID; }
} //Fish

class Trout extends Fish implements Edible {
	protected String className = "Trout";
	public String toString() { return className; }
	public void eat() {}
} // Trout

class Speckled extends Trout {	
	public Speckled() { className = "Speckled"; }	
	public String toString() { return className; }

}//Speckled

class Rainbow extends Trout {	
	public Rainbow() { className = "Rainbow"; } 
	public String toString() { return className; }
}

class Brown extends Trout {
	public Brown() { className = "Brown"; }
	public String toString() { return className; }
} //Brown

