# Upcast vermeiden



## theomega (6. Aug 2006)

Hallo Leute,
hab da so ein Problem: 

```
public class SmallClass {
	int intvalue;
	
	public void setIntValue(int i) {
		this.intvalue = i;
	}
	
	public int getIntValue() {
		return(intvalue);
	}
	
	public SmallClass combine(SmallClass sec) {
		SmallClass re = new SmallClass();
		re.setIntValue(this.getIntValue()+sec.getIntValue());
		return(re);		
	}
}

public class BigClass extends SmallClass {
	String strvalue;
	
	public String getStringValue() {
		return(strvalue);
	}
	
	public void setStringValue(String s) {
		this.strvalue = s;
	}
	
	public BigClass combine(BigClass sec) {
		BigClass re = (BigClass)super.combine(sec);
		re.setStringValue(this.getStringValue()+" "+sec.getStringValue());
		return(re);		
	}
}

public class UpcastTest {
	public static void main(String[] args) {
		//Das funktioniert:
		SmallClass seins = new SmallClass();
		SmallClass szwei = new SmallClass();
		seins.setIntValue(10);
		szwei.setIntValue(5);
		SmallClass sresult = seins.combine(szwei);
		System.out.println("Kombiniert ergibt das: "+sresult.getIntValue());
		
		//Und das funktioniert nicht:
		BigClass beins = new BigClass();
		BigClass bzwei = new BigClass();
		beins.setIntValue(10);
		beins.setStringValue("Eins");
		bzwei.setIntValue(5);
		bzwei.setStringValue("Zwei");
		BigClass bresult = beins.combine(bzwei);
		System.out.println("Kombiniert ergibt das: "+bresult.getIntValue()+"/"+bresult.getStringValue());
	}
}
```

Sinn der Sache ist folgendes: SmallClass speichert bestimmte Daten (in dem Fall einen integer-Wert). Big-Class soll zusätzlich dazu noch weitere Werte speichern (hier: String). Es gibt jetzt für beide eine Methode combine. Diese soll zwei Klassen kombinieren und zwar die Werte zusammenzählen. Leider ist mir unklar wie man das in der BigClass realisiert. Der Type-Cast schlägt so natürlich fehl, weil ich einen Upcast versuche der so ja nicht geht. Wie löst man sowas richtig? Ich könnte natürlich einfach den Code aus der Smallclass kopieren, aber das will ich vermeiden.

Danke
TO


----------



## foobar (6. Aug 2006)

Du könntest die Methode combine nur in der Oberklasse definieren und dann auf SmallClass casten. Oder du definierst dir ein Interface das beide Klasse implementieren.


----------



## theomega (6. Aug 2006)

Hy,
danke für die Antworten, aber ich verstehs nicht ganz:
Wenn ich die combine in der BigClass weglasse, dann werden doch alle Werte aus der BigClass garnicht verarbeitet, ist ja nicht sinn der Sache!

Wie würde das mit dem Interface funktionieren? Könntest du das kurz anreisen, ich versteh nicht ganz wie mir das helfen könnte!

Danke
TO


----------



## foobar (6. Aug 2006)

```
interface Combineable
{
    public Combineable combine(Combineable comb);
    public int getValue();
    public void setValue(String value);
}

class SmallClass implements Combineable
{
    private int intvalue;

    public void setIntValue(int i)
    {
        this.intvalue = i;
    }

    public int getIntValue()
    {
        return (intvalue);
    }

    public Combineable combine(Combineable comb)
    {
        comb.setValue(getValue()+comb.getValue()+"");
        return comb;
    }

    public int getValue()
    {
        return intvalue;
    }

    public void setValue(String value)
    {
        this.intvalue =  Integer.parseInt(value);
    }
}


class BigClass implements Combineable
{
    String strvalue;

    public String getStringValue()
    {
        return (strvalue);
    }

    public void setStringValue(String s)
    {
        this.strvalue = s;
    }

    public Combineable combine(Combineable comb)
    {
        comb.setValue(getValue()+comb.getValue()+"");
        return comb;
    }

    public int getValue()
    {
        return Integer.parseInt(strvalue);
    }

    public void setValue(String value)
    {
        strvalue = value;
    }
}


public class UpcastTest
{
    public static void main(String[] args)
    {
        // Das funktioniert:
        SmallClass seins = new SmallClass();
        SmallClass szwei = new SmallClass();
        seins.setIntValue(10);
        szwei.setIntValue(5);
        Combineable sresult = seins.combine(szwei);
        System.out.println("Kombiniert ergibt das: " + sresult.getValue());

        // Und das funktioniert nicht:
        BigClass beins = new BigClass();
        BigClass bzwei = new BigClass();
        beins.setValue("10");
        bzwei.setValue("5");
        Combineable bresult = beins.combine(bzwei);
        System.out.println("Kombiniert ergibt das: " + bresult.getValue());
    }
}
```

Das Beispiel ansich macht zwar keinen Sinn, aber es verdeutlich wie Polymorphie funktioniert. Du könntest das auch mit einer Oberklasse oder einer abstrakten Oberklasse lösen.


----------



## theomega (6. Aug 2006)

Klaro, so gehts, aber das hilft ja nicht weiter. Die Big-Class soll ja auch den Integer noch kombinieren, das tut er bei dir nicht und genau das ist doch der Knackpunkt oder nicht?

Danke
TO


----------



## foobar (6. Aug 2006)

> Klaro, so gehts, aber das hilft ja nicht weiter. Die Big-Class soll ja auch den Integer noch kombinieren, das tut er bei dir nicht und genau das ist doch der Knackpunkt oder nicht?


Was genau ist denn das Ziel der Übung? Ich dachte es geht um Vererbung und Polymorphie.


----------



## Illuvatar (6. Aug 2006)

Komplizierte Sache hier, du hast Glück für das Rhapsody-Zitat in der Sig, sonst hätt ich schon aufgegeben nachzudenken 

@foobar: Sein Problem ist afaik, dass die eine Klasse eben von der anderen abgeleitet ist und von beiden die Methode aufgerufen werden soll.

@theomega: Wie du vielleicht schon festgestellt hast, wenn das nicht immer ein neues Objekt sein sollte, das zurückgegeben wird, wäre das ganze einfacher. Man könnte die Methode so in der Art machen:

```
public BigClass combine(BigClass sec) {
      super.combine(sec);
      this.setStringValue(this.getStringValue()+" "+sec.getStringValue());
      return(this);
   }
```
Und hier setzt meine Idee an: Wenn man eine zweite interne Methode einfügt, die genau das hier macht, und eine Möglichkeit das Objekt zuerst zu kopieren, und dann die Methode aufzurufen, kann man das hinkriegen. Naja, Code sagt mehr als 1000 Worte:

```
class SmallClass implements Cloneable{
   int intvalue;

   public void setIntValue(int i) {
      this.intvalue = i;
   }

   public int getIntValue() {
      return(intvalue);
   }

   public SmallClass combine(SmallClass sec) {
      try{
          SmallClass re = (SmallClass)this.clone();
          re.combineInternal(sec);
          return(re);
      }catch (CloneNotSupportedException e){
          e.printStackTrace();
          return null;
      }
   }
   
   void combineInternal(SmallClass sec)
   {
      this.setIntValue(this.getIntValue()+sec.getIntValue());
   }
}

class BigClass extends SmallClass {
   String strvalue;

   public String getStringValue() {
      return(strvalue);
   }

   public void setStringValue(String s) {
      this.strvalue = s;
   }

   public BigClass combine(BigClass sec) {
      try{
          BigClass re = (BigClass)this.clone();
          re.combineInternal(sec);
          return(re);
      }catch (CloneNotSupportedException e){
          e.printStackTrace();
          return null;
      }
   }
   
   void combineInternal(BigClass sec)
   {
     super.combineInternal(sec);
     this.setStringValue(this.getStringValue()+" "+sec.getStringValue());
   }
}

public class UpcastTest {
   public static void main(String[] args) {
      //Das funktioniert:
      SmallClass seins = new SmallClass();
      SmallClass szwei = new SmallClass();
      seins.setIntValue(10);
      szwei.setIntValue(5);
      SmallClass sresult = seins.combine(szwei);
      System.out.println("Kombiniert ergibt das: "+sresult.getIntValue());

      //Und das funktioniert nicht:
      BigClass beins = new BigClass();
      BigClass bzwei = new BigClass();
      beins.setIntValue(10);
      beins.setStringValue("Eins");
      bzwei.setIntValue(5);
      bzwei.setStringValue("Zwei");
      BigClass bresult = beins.combine(bzwei);
      System.out.println("Kombiniert ergibt das: "+bresult.getIntValue()+"/"+bresult.getStringValue());
   }
}
```

Wenn man sich das anschaut, sind die beiden combine-Methoden jetzt nahezu identisch. Und mit ein paar Änderungen muss BigClass diese nicht überschreiben. Ein letzter Codeblock:


```
class SmallClass implements Cloneable{
   int intvalue;

   public void setIntValue(int i) {
      this.intvalue = i;
   }

   public int getIntValue() {
      return(intvalue);
   }

   public SmallClass combine(SmallClass sec) {
      try{
          SmallClass re = (SmallClass)this.clone();
          re.combineInternal(sec);
          return(re);
      }catch (CloneNotSupportedException e){
          e.printStackTrace();
          return null;
      }
   }
   
   void combineInternal(SmallClass sec)
   {
      this.setIntValue(this.getIntValue()+sec.getIntValue());
   }
}

class BigClass extends SmallClass {
   String strvalue;

   public String getStringValue() {
      return(strvalue);
   }

   public void setStringValue(String s) {
      this.strvalue = s;
   }
   
   void combineInternal(SmallClass sec)
   {
     super.combineInternal(sec);
     if (sec instanceof BigClass){
       BigClass bc = (BigClass)sec;
       this.setStringValue(this.getStringValue()+" "+bc.getStringValue());
     }
   }
}

public class UpcastTest {
   public static void main(String[] args) {
      //Das funktioniert:
      SmallClass seins = new SmallClass();
      SmallClass szwei = new SmallClass();
      seins.setIntValue(10);
      szwei.setIntValue(5);
      SmallClass sresult = seins.combine(szwei);
      System.out.println("Kombiniert ergibt das: "+sresult.getIntValue());

      //Und das funktioniert nicht:
      BigClass beins = new BigClass();
      BigClass bzwei = new BigClass();
      beins.setIntValue(10);
      beins.setStringValue("Eins");
      bzwei.setIntValue(5);
      bzwei.setStringValue("Zwei");
      BigClass bresult = (BigClass)beins.combine(bzwei);
      System.out.println("Kombiniert ergibt das: "+bresult.getIntValue()+"/"+bresult.getStringValue());
   }
}
```


----------

