/************************************************************************/
/* Prof. Dr. Carsten Vogt                                               */
/* FH Koeln, Fak. 07 / Nachrichtentechnik                               */
/* http://www.nt.fh-koeln.de/vogt                                       */
/*                                                                      */
/* Das Programm zeigt zunaechst, welche Zuweisungen zwischen Ober- und  */
/* Unterklassen-Variablen und -Objekten zulaessig sind und welche zu    */
/* Compiler- oder Laufzeitfehlern fuehren.                              */
/* Anschliessend werden zulaessige und nicht zulaessige Methodenaufrufe */
/* angegeben.                                                           */
/*                                                                      */
/* Fuer die Zulaessigkeit von Zuweisungen gelten die folgenden Regeln:  */
/*                                                                      */
/* Stets zulaessig:                                                     */
/*                                                                      */
/*  <Objektvariable der Oberklasse> = <Objektvariable der Oberklasse>   */
/*  auch <Objektvariable der Oberklasse> = new (<Oberklasse>)           */
/*                                                                      */
/*  <Objektvariable der Unterklasse> = <Objektvariable der Unterklasse> */  
/*  auch <Objektvariable der Unterklasse> = new (<Unterklasse>)         */
/*                                                                      */
/*  <Objektvariable der Oberklasse> = <Objektvariable der Unterklasse>  */
/*  auch <Objektvariable der Oberklasse> = new (<Unterklasse>)          */
/*                                                                      */
/* Nie zulaessig (Compilerfehler "incompatible types"):                 */
/*                                                                      */
/*  <Objektvariable der Unterklasse> = <Objektvariable der Oberklasse>  */
/*                                                                      */
/*  <Objektvariable der Unterklasse> = new (<Oberklasse>)               */    
/*                                                                      */
/* Moeglicherweise zulaessig:                                           */   
/*                                                                      */
/*  <Objektvariable der Unterklasse>                                    */
/*      = (<Unterklasse>) <Objektvariable der Oberklasse>               */
/*                                                                      */
/*  (Explizite Typumwandlung = "Down-Cast" von Ober- zu Unterklasse.    */
/*   Kein Compilerfehler,                                               */
/*   aber evtl. Laufzeitfehler "ClassCastException",                    */
/*   wenn Objektvariable der Oberklasse nicht auf ein Objekt            */
/*   der Unterklasse verweist.)                                         */
/*                                                                      */
/************************************************************************/

/* Definition einer Ober- und einer Unterklasse */

class Oberklasse {
 int attr1;
 void setAttr(int wert1) {
  attr1=wert1;
 }
}

class Unterklasse extends Oberklasse {
 int attr2;
 void setAttr(int wert1, int wert2) {
  attr1=wert1;
  attr2=wert2;
 }
}

public class ObjZuweisungen {

 public static void main(String[] args) {

  /* Zulaessige und nicht zulaessige Objektzuweisungen */

  Oberklasse a1 = new Oberklasse();
  Unterklasse a2  = new Unterklasse();

  Oberklasse b1 = new Unterklasse();
  Unterklasse b2 = new Oberklasse();    // Compilerfehler

  Oberklasse c1 = new Oberklasse();
  Unterklasse c2 = c1;                  // Compilerfehler

  Oberklasse d1 = new Oberklasse();
  Unterklasse d2 = (Unterklasse) d1;    // Laufzeitfehler

  Oberklasse e1 = new Unterklasse();
  Unterklasse e2 = e1;                  // Compilerfehler

  Oberklasse f1 = new Unterklasse();
  Unterklasse f2 = (Unterklasse) f1;

  Unterklasse g2 = new Unterklasse();
  Oberklasse g1 = g2;

  Unterklasse h2 = new Oberklasse();    // Compilerfehler
  Oberklasse h1 = h2;                   // [ Compilerfehler ]

  Unterklasse i2 = new Oberklasse();    // Compilerfehler
  Oberklasse i1 = (Oberklasse) i2;      // [ Compilerfehler ]

  /* Zulaessige und nicht zulaessige Methodenaufrufe */

  Oberklasse j1 = new Oberklasse();
  j1.setAttr(1);
  j1.setAttr(1,2);                      // Compilerfehler

  Unterklasse k1 = new Unterklasse();
  k1.setAttr(1);
  k1.setAttr(1,2);

  Oberklasse l1 = new Oberklasse();
  ((Unterklasse)l1).setAttr(1,2);       // Laufzeitfehler

  Oberklasse m1 = new Unterklasse();
  ((Unterklasse)m1).setAttr(1,2);

 }

}

