# Datentyp zur Laufzeit änderbar?



## Rudolf (30. Okt 2012)

Hi,

ich hatte in einer funktionalen Programmiersprache eine Abstraktionsmethode, die ich in Java sehr vermisse. Es geht darum, dass man einen Obertypen hat und beispielsweise drei Untertypen, die den Obertypen erweitern. Alle Untertypen haben einen Konstruktor, der eine Zahl vom Typ int akzeptiert. Je nachdem welcher int Value eingegeben wird, wird der passende Untertyp ausgewählt.

Daher meine Frage. Gibt es in Java doch eine Möglichkeit, dass die Klasse von einem Typ je nach Eingabe entscheidet welchen Typ es zur Laufzeit annimmt. 

Ich möchte sowas schreiben wie: 


```
IntegerWrapper wrapper = new IntegerWrapper(int)
if (int==1) wrapper instanceof IntegerOneWrapper == true
if (int==2) wrapper instanceof IntegerTwoWrapper == true
if (int==3) wrapper instanceof IntegerThreeWrapper == true
```

Die einzige Möglichkeit, die mir sonst einfällt, wäre sowas:


```
private static IndexInteger getIndexInteger(int integer) {
		switch (integer) {
		case 0:
			return new IndexIntegerOne();
		case 1:
			return new IndexIntegerTwo();
		case 2:
			return new IndexIntegerThree();
		default:
			throw new IllegalArgumentException();
		}
	}
```
Aber das sieht irgendwie hässlich aus.


----------



## Firephoenix (30. Okt 2012)

Das untere sieht für den Fall dann eigentlich richtig aus.

Hast du einen konkreten Anwendungsfall bei dem du wirklich auf die Typen von Java-Klassen angewiesen bist und nicht sowas schreiben kannst wie new Wrapper(int) bzw wrapper.getWrappedValue()?

Gruß


----------



## Rudolf (30. Okt 2012)

Also konkreter Anwendungsfall.


```
public class Test {

	public static void main(final String[] args) {
		Waiter waiter = new Waiter(new Field(), new Field(), new Field());
		waiter.operation(1);
	}

	static class Waiter {
		Field fieldOne;
		Field fieldTwo;
		Field fieldThree;

		public Waiter(Field fieldOne, Field fieldTwo, Field fieldThree) {
			this.fieldOne = fieldOne;
			this.fieldTwo = fieldTwo;
			this.fieldThree = fieldThree;
		}

		public void operation(int value) {
			if (value == 1) {
				fieldOne.operation();
			}
			if (value == 2) {
				fieldTwo.operation();
			}
			if (value == 3) {
				fieldThree.operation();
			}
		}

		public void operation(IntegerWrapper wrapper) {
			// möchte ich gerne haben
			wrapper.operation(fieldOne, fieldTwo, fieldThree);
		}

	}

	static interface IntegerWrapper {

		void operation(Field fieldOne, Field fieldTwo, Field fieldThree);

	}

	static class IntegerOneWrapper implements IntegerWrapper {

		@Override
		public void operation(Field fieldOne, Field fieldTwo, Field fieldThree) {
			fieldOne.operation();
		}

	}

	static class IntegerTwoWrapper implements IntegerWrapper {

		@Override
		public void operation(Field fieldOne, Field fieldTwo, Field fieldThree) {
			fieldTwo.operation();
		}

	}

	static class IntegerThreeWrapper implements IntegerWrapper {

		@Override
		public void operation(Field fieldOne, Field fieldTwo, Field fieldThree) {
			fieldThree.operation();
		}

	}

	static class Field {
		public void operation() {
			System.out.println("Operation");
		}
	}
}
```

D.h. ich habe drei Felder und ich kriege einen int value zwischen 1 und 3. je nachdem welcher int value gegeben wird, soll auf einem Feld die Operation ausgeführt werden. Das ganze möchte ich mit Polymorphie lösen, weil dieses if abfragen nicht objektorientiert sind. Am liebsten hätte ich gerne eine Spezialisierung von int 1, int 2 und int 3. Zu Not würde ich Wrapperklassen bauen. Aber für die Wrapperklassen bräuchte ich eine Methode, die den richtigen Untertyp ausgewählt, also für 1 WrapperOneInteger, für 2 WrapperTwoInteger usw. Wenn ich aber wie oben gepostet den switch Code verwende, kann ich ja gleich die if Abfragen wie aus diesem Beispiel machen. 

Wie würde man das Problem elegant objektorientiert lösen?


----------



## bygones (30. Okt 2012)

schonmal was von Interface gehoert ? What Is an Interface? (The Java™ Tutorials > Learning the Java Language > Object-Oriented Programming Concepts)


----------



## Rudolf (30. Okt 2012)

bygones hat gesagt.:


> schonmal was von Interface gehoert ? What Is an Interface? (The Java™ Tutorials > Learning the Java Language > Object-Oriented Programming Concepts)



Du scheinbar nicht, sonst hättest du in meinem Code gesehen, dass ich ein Interface verwende, du Schlaumeier.


----------



## Ghostfish (30. Okt 2012)

Rudolf hat gesagt.:


> ```
> private static IndexInteger getIndexInteger(int integer) {
> switch (integer) {
> case 0:
> ...



Ich weiß nicht, ob es dir viel bringt, aber statt der switch-Geschichte kann man natürlich die Class-Objekte in ein Array packen und dann per Index auf sie zugreifen und per Reflection instanziieren.

Etwa

```
Class[] classes = {Integer.class, Double.class, String.class};
```

Ich weiß nicht, worauf das Ganze hinausführen soll. Man kann natürlich noch eleganter auch gleich statt eines int-Wertes die Klasse als Parameter mitgeben.


----------



## bygones (31. Okt 2012)

Rudolf hat gesagt.:


> Du scheinbar nicht, sonst hättest du in meinem Code gesehen, dass ich ein Interface verwende, du Schlaumeier.


heisst anscheinend nicht scheinbar.

hab ich uebersehen - verzeihung. Dennoch kann man auch mit einem anderen Ton hier antworten, vor allem wenn man hilfe fragt


----------



## Gast2 (31. Okt 2012)

Das Beispiel macht in meinen Augen wenig Sinn. 
Werden in Waiter alle drei Field Instanzen benötigt? Oder wird da nur eine gebraucht?
Warum machst du aus der einen Methode nicht drei Methoden: operationOnFieldOne(), etc.

Das lässt sich auf jedenfall schöner lösen.


----------



## Rudolf (31. Okt 2012)

Es ist doch ganz einfach.

Kriegt ein Objekt eine 1 als Parameter für den Objektkonstruktor soll das Objekt den Datentyp WrapperOne annehmen, bei 2 WrapperTwo und bei 3 WrapperThree. Ist das jetzt elegant zu lösen in Java oder nicht? Das ist alles was ich wissen will.


----------



## Firephoenix (31. Okt 2012)

Das ist eher schon eine Lösungsbeschreibung für das switch-Statement von oben 

Was soll das ganze denn am Ende machen wenn es fertig ist, bzw was ist das eigentliche Problem?

Gruß


----------



## Rudolf (1. Nov 2012)

Es gibt kein Problem, es ist nur eine prinzipielle Frage.

Die Idee ist, dass das Objekt selber seinen Datentyp je nach Parameter auswählt. Und ich meinte ja schon oben dass die Lösung mit switch funktioniert, aber nicht sonderlich objektorientiert ist. Ich suche nach einer objektorientierten Lösung für mein Problem.


----------



## JCODA (1. Nov 2012)

Vielleicht, in diesem speziellen Fall, wenn es darum geht per Integer drauf zuzugreifen, wie wärs mit nem varargs-Waiter-Konstruktor? bzw generell n Array oder ne Map ? Aber irgendwie gefallen tut mir das auch nicht :/


----------



## Rudolf (1. Nov 2012)

Ja so richtig geht das in Java nicht und das finde ich ziemlich schade, weil es Potenzial verschenkt. Weiß jemand ob sowas als Feature in einer zukünftigen java version geplant ist?


----------



## bygones (1. Nov 2012)

Rudolf hat gesagt.:


> Es ist doch ganz einfach.
> 
> Kriegt ein Objekt eine 1 als Parameter für den Objektkonstruktor soll das Objekt den Datentyp WrapperOne annehmen, bei 2 WrapperTwo und bei 3 WrapperThree. Ist das jetzt elegant zu lösen in Java oder nicht? Das ist alles was ich wissen will.



die Frage ist doch, warum bekommt es eine 1, 2, oder 3 und nicht einfach den gebrauchten Datentyp ?

auch ich versteh nicht wirklich was das Bsp zeigen soll und worum es prinzipiell geht. Wenn du einen primitiven Typ auf Objekte mappen willst musst du das mappen beschreiben. 

Ich seh hier weder ein verschenktes Potenzial noch Nachteile, aber liegt wahr. daran, dass ich nicht versteh was der Sinn sein soll


----------



## Ghostfish (1. Nov 2012)

Verstehe auch nicht das Problem. Wenn ein Index als Parameter übergeben werden soll, muss es immer urgendwo ein Mapping auf den Datentyp geben, ob mit switch oder einem Array, wie in #6 beschrieben. Ansonsten kann man einfach den Datentyp als Parameter übergeben: 


```
private static IndexInteger getIndexInteger(Class aClass) {
		try {
			return (IndexInteger)aClass.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return null;
	}
```


----------

