Datentyp zur Laufzeit änderbar?

Rudolf

Bekanntes Mitglied
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:

Java:
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:

Java:
	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.
 
F

Firephoenix

Gast
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

Bekanntes Mitglied
Also konkreter Anwendungsfall.

Java:
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?
 
Zuletzt bearbeitet:

Ghostfish

Mitglied
Java:
	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.

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
Code:
		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.
 
Zuletzt bearbeitet:
G

Gast2

Gast
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

Bekanntes Mitglied
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.
 
F

Firephoenix

Gast
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

Bekanntes Mitglied
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

Top Contributor
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

Bekanntes Mitglied
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?
 
B

bygones

Gast
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

Mitglied
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:

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

Ähnliche Java Themen


Oben