PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : zwei kurze Java-Fragen (nur noch eine)


registrierter Gast
2005-11-05, 04:17:10
Bin noch relativ neu in Java und habe zwei kurze Fragen.
Ich habe ein Array 'zeile', welches ich der ersten Dimension eines zweidimensionalen Arrays 'feld' (Größe: m x n, mit m <> n) zuweisen möchte. Habe aber keine Ahnung, wie ich das anstellen soll. :uponder: Bisher gelang es mir nur, das Array 'zeile' der zweiten Dimension von 'feld' zuzuweisen und zwar mit:
feld[i] = zeile;

Bei
feld = zeile;
bricht der Compiler verständlicherweise mit einer Fehlermeldung ab (found: float[], required[][]).
Derartiges wie feld [i], feld[][i], feld[:][i] funktioniert nicht! :(

Als Notlösung könnte ich mir vorstellen, daß man Zeile und Spalte des Arrays vertauscht und nach dem einlesen, das Array transponieren!



Außerdem habe ich zwei Methoden,
1: public int[] extract (String line, int length)
2: public float[] extract (String line, int length)
welche das Gleiche tun, nur daß Methode 1 Integer aus einem String extrahiert und Methode 2 Gleitkommazahlen.
In C++ würde dies mit Templates funktionieren. Gibt es entsprechendes für Java?

edit:
Vergeßt die zweite Frage. Nach weiterem googlen, stellte sich heraus, daß das Templates-Konzept aus C++ in Java 'Generics' heißt und ab Version 1.5 unterstützt wird. Da ich aber eine Kompatibilität zu v1.4 wahren wollte, erübrigt sich das wohl erstmal. :redface:

Monger
2005-11-05, 10:31:17
Zu Frage eins: Afaik geht das nicht so einfach. Im Speicherbereich sieht es ja so aus, dass die Felder der zweiten Dimension hintereinander weg liegen, deshalb kannst du da einen Bereich problemlos überschreiben.

Aber wenn du ein Array mit zwei Indizes hast, ist es einzig und allein deine Interpretation, dass dieses aus Spalte und Zeile besteht. Das einfächste wäre wohl, sich eine Hilfsmethode zu schreiben à la:



void fillRow(int [][] array, int rowNo, int [] line){

// die Arraybreite musst du natürlich auch noch irgendwo mitschleppen.
for(int i = 0; i < linesize; i++)
array[i][rowNo] = line [i];
}

Das array ist (wenn ich jetzt nicht völlig daneben liege) ein Basisdatentyp, wird also nicht referenziert, d.h. du musst dann das Ergebnis wieder auf das ursprüngliche Array zurückschreiben.

Das wird letztendlich ein bisschen hässlich aussehen.

registrierter Gast
2005-11-05, 20:04:02
Okay, danke.
Bevor ich mich wieder wegen fehlendem 'call-by-reference' in Java :ucrazy2: (echt tolle Programmiersprache :rolleyes:) sonst wie verbiegen muss, hab ich nun doch m und n gewechselt und tausche bei der Abfrage-Methode einfach intern die Koordinaten.

RoKo
2005-11-06, 02:00:52
Das array ist (wenn ich jetzt nicht völlig daneben liege) ein Basisdatentyp, wird also nicht referenziert
Du liegst daneben, Arrays werden referenziert. In dem Fall sogar nicht nur einmal denn [][] ergibt in Java keine Matrix, sondern einen Array von Arrays.

registrierter Gast
2005-11-15, 16:09:12
Habe zwei neue Probleme in Java.

Bin jetzt in Kapitel 30 und habe in meinem Programm ein Kontextmenü implementiert. Es erscheint tatsächlich...
aber leider nur unter Windows. Wenn ich Linux (Knoppix) verwende, wird der Rechtsklick lediglich als normaler Mausklick registriert. Von den Schwierigkeiten mit 'isMetaDown()' habe ich gehört, also nutzte ich von vornherein 'MouseEvent.isPopupTrigger()'. Bewirkt aber anscheinend das Gleiche, wie 'isMetaDown()'.
Gibt es da einen funktionierende Möglichkeit?
Und was ist die Meta-Taste in Linux?!?


Außerdem habe ich ein Problem mit der repaint-Methode.
Nach einem Mausklick, sollte das Programm das Fenster eigentlich neu zeichnen

if(!event.isPopupTrigger()) {
int X = event.getX() - getInsets().left, Y = event.getY() - getInsets().top;
target_clicked.assign(getCoords(X, Y));
secondCoords_chosen = true;
calculate = true;
repaint(); //<= wird nicht aufgerufen
calculate(); //diverse zeitaufwendige Berechnungen werden durchgeführt
drawWay = true;
repaint();
}

Doch 'repaint()' reagiert überhaupt nicht.
Habe in der überlagerten paint-Methode eine System.out-Ausgabe gesetzt, die immer etwas ausgibt, wenn paint aufgerufen wird. Bei dem genannten 'repaint()' findet diese Ausgabe nicht statt, 'paint' wird also nicht aufgerufen!
Habe es auch in 'calculate()' mit repaint probiert, aber auch da Fehlanzeige!
Wenn ich die letzten drei Zeilen, der oben genannten if-Anweisung auskommentiere, funktioniert 'repaint()' einwandfrei.
Kann es daran liegen, daß der Rechner bei 'calculate()' mehrere Sekunden 100% ausgelastet ist? Das Fenster wird nämlich ebenfalls nicht neu gezeichnet, wenn ich es minimiere und anschließend wieder aufrufe.
Wenn es daran liegt, wie kann ich dem Zeichnen Priorität geben?



ps. das 'repaint()' nach 'calculate()' funktioniert wieder.

Abe Ghiran
2005-11-15, 17:22:27
repaint() zeichnet nicht sofort neu, sondern stellt die Anforderung zum neuzeichnen nur in den EDT. Dabei können auch mehrere Aufrufe von repaint zu einem zusammen gefasst werden.
Wenn du dich jetzt gerade selber im EDT befindest, wird dein Fenster erst dann neugezeichnet, wenn dein Code fertig ist und der EDT sich eben dem neuzeichnen widmen kann.

Eventuell hilft dir paintImmediately oder du rufst repaint auf und lässt die anderen Sachen danach mit SwingUtilities.invokeLater ausführen.

Grüße, Jan

Coda
2005-11-15, 17:35:10
Okay, danke.
Bevor ich mich wieder wegen fehlendem 'call-by-reference' in Java :ucrazy2: (echt tolle Programmiersprache :rolleyes:) sonst wie verbiegen muss, hab ich nun doch m und n gewechselt und tausche bei der Abfrage-Methode einfach intern die Koordinaten.Alle Nicht-POD-Datatypen werden in Java per Referenz übergeben.

registrierter Gast
2005-11-15, 20:35:29
Eventuell hilft dir paintImmediately oder du rufst repaint auf und lässt die anderen Sachen danach mit SwingUtilities.invokeLater ausführen.

Grüße, JanDanke, werde ich mal probieren. :)

Alle Nicht-POD-Datatypen werden in Java per Referenz übergeben.Danke, mittlerweile weiß ich's auch. Lediglich die primitiven Datentypen werden als 'call-by-value' übergeben. Damals (vor zwei Wochen, als ich mit Java begann) habe ich noch extra ein Objekt erstellt und dieses dann der Methode übergeben :ulol:, aber geht ja zum Glück auch einfacher.


Update:
'paintImmediately()' gilt nur für Swing, welches erst ab Kapitel 36 behandelt wird :eek: und nutze bis dahin noch awt.
Nachdem das Fenster aber nach einer Milliarde Multiplikationen zweier double-Zahlen immernoch nicht refreshen wollte (immerhin 5min später), hatte ich genug davon und umging das Ganze mit einem schmutzigen Trick. Nun wird in der paint-Methode selbst, die Berechnungsmethode aufgerufen. :rolleyes:


Das Problem mit dem Kontextmenü unter Linux konnte ich ebenfalls lösen, indem statt event.isPopupTrigger() die gedrückte Taste ('getButton()') mit MouseEvent.BUTTON3 (die rechte Taste) verglichen wird.

Tommes
2005-11-17, 01:43:12
Also wir haben an der Uni gelernt, dass man in Listener keine komplexen Berechnungen packen sollte, sondern dies nur "anstoßen" soll (Stichwort Threads).

Senior Sanchez
2005-11-17, 11:06:46
Also wir haben an der Uni gelernt, dass man in Listener keine komplexen Berechnungen packen sollte, sondern dies nur "anstoßen" soll (Stichwort Threads).

Joar, damit man den Event-Dispatch-Thread nicht solange blockiert. Deswegen sollte man sowas möglichst kompakt und simpel halten.

registrierter Gast
2005-11-17, 19:55:41
Also wir haben an der Uni gelernt, dass man in Listener keine komplexen Berechnungen packen sollte, sondern dies nur "anstoßen" soll (Stichwort Threads).(y) Das Stichwort war ja mal richtig geil. :biggrin:
Alle Probleme haben sich in Luft aufgelöst und kann jetzt sogar zu dem nächsten Schritt gehen, daß er je nach Position des Mauszeigers Berechnungen durchführt (deren Anstoß nach wie vor nur im Listener steht) und diese abbricht, sobald sich die Maus bewegt und eine andere Berechnung beginnt.


Man mag zwar von Java halten, was man will...
ob man nun die Dinge vermisst, die man an C++ so lieb gewonnen hat oder J. nicht die Schnelligkeit erreicht, die man mit Fortran hatte bzw. sich gern deren einfache Handhabung von Arrays wünscht...
aber Java ist so Scheiße einfach (sorry für den Ausdruck :rolleyes:). Das ist schon fast eine Freude. :smile:

Senior Sanchez
2005-11-17, 20:35:48
(y) Das Stichwort war ja mal richtig geil. :biggrin:
Alle Probleme haben sich in Luft aufgelöst und kann jetzt sogar zu dem nächsten Schritt gehen, daß er je nach Position des Mauszeigers Berechnungen durchführt (deren Anstoß nach wie vor nur im Listener steht) und diese abbricht, sobald sich die Maus bewegt und eine andere Berechnung beginnt.


Man mag zwar von Java halten, was man will...
ob man nun die Dinge vermisst, die man an C++ so lieb gewonnen hat oder J. nicht die Schnelligkeit erreicht, die man mit Fortran hatte bzw. sich gern deren einfache Handhabung von Arrays wünscht...
aber Java ist so Scheiße einfach (sorry für den Ausdruck :rolleyes:). Das ist schon fast eine Freude. :smile:

Java ist nicht schwer :)
Aber viele Dinge, das bekommste nur mit der Zeit mit, also gute Programme schreibste mit Java auch nicht einfach mal so ;) Sprich, es ist einfach zu lernen, aber erfordert einiges an können, wenn man es meistern will.

michl
2005-11-17, 21:08:57
Java ist nicht schwer :)
Aber viele Dinge, das bekommste nur mit der Zeit mit, also gute Programme schreibste mit Java auch nicht einfach mal so ;) Sprich, es ist einfach zu lernen, aber erfordert einiges an können, wenn man es meistern will.
Full Acknowledge

Wenn ich an das Thema Threads und Synchronisation denke, dann kann man noch so viele Bücher und Artikel lesen, es ist immer wieder eine Herausforderung.
Und bei Java Swing entdecke ich auch immer wieder was neues.
Aber meiner Meinung nach, ist Java zur Zeit die beste Programmiersprache (ich weiß, es kommt immer auf die Anwendung drauf an, trotzdem bleib ich dabei :smile: )

lg
michl

Monger
2005-11-17, 21:12:19
Java ist nicht schwer :)
Aber viele Dinge, das bekommste nur mit der Zeit mit, also gute Programme schreibste mit Java auch nicht einfach mal so ;) Sprich, es ist einfach zu lernen, aber erfordert einiges an können, wenn man es meistern will.

Ich stell mal die provokante These, dass ein Vergleich zwischen C++ und Java sowieso unangemessen ist. Richtig wäre ein Vergleich zwischen den MS managed languages und Java. Und da schenken sich beide afaik nicht sooo viel.

Senior Sanchez
2005-11-17, 21:38:44
Ich stell mal die provokante These, dass ein Vergleich zwischen C++ und Java sowieso unangemessen ist. Richtig wäre ein Vergleich zwischen den MS managed languages und Java. Und da schenken sich beide afaik nicht sooo viel.

Ja das stimmt natürlich, der Vergleich hinkt irgendwo. Aber Java vs. C++ das ist schon son ewiger Kampf und Vergleich, trotz der Verschiedenheit der Sprachen, das hat sich so eingebrannt die miteinander zu vergleichen.

Coda
2005-11-17, 22:18:08
Ich glaube der Kampf geht allg. eher um kompiliert vs. managed. Ich bin da neutral, ich halte managed nur nicht in allen Fällen für so sinnvoll wie es angepriesen wird von manchen Anbetern.

Monger
2005-11-18, 11:35:38
Ich glaube der Kampf geht allg. eher um kompiliert vs. managed. Ich bin da neutral, ich halte managed nur nicht in allen Fällen für so sinnvoll wie es angepriesen wird von manchen Anbetern.

Managed heißt doch nichts anderes, als dass eine maschinenneutrale Zwischensprache erzeugt wird, oder?

(Sorry für OT, aber die ursprünglichen Fragen scheinen mir geklärt)
Zumindest für mich ist das völlig uninteressant. Was ich viel spannender finde, sind die Sprachfeatures. Typensicherheit z.B. ist - imo völlig zu Recht - ein riesengroßes Thema.

Java empfinde ich als extrem "saubere" Sprache, die vielleicht nicht alles bietet was ein Profi gerne hätte, aber einen unglaublich sauberen, lesbaren und sicheren Code erzwingt oder zumindest nahe legt. In C++ kann man ohne große Kenntnisse ganz fürchterliche Abstürze produzieren.

Mein ehemaliger Dozent hat das mit "Blue Pill vs Red Pill " verglichen: nehme ich die blaue Pille und bleibe in meiner gut behüteten, sauberen Welt, aber mit mangelhafter Kontrolle? Oder möchte ich die volle Kontrolle, muss aber dafür die vielen hässlichen Details und Untiefen hinnehmen?

Er hat übrigens gemeint, KEIN vernünftiger Entwickler will die rote Pille! :D

registrierter Gast
2005-11-22, 04:14:52
Ich arbeite nun mit einer ArrayList, besser gesagt mit Zweien. Eine enthält die Zwischenergebnisse 'act_way' der aktuellen Berechnung, während in der anderen die Endergebnisse 'opt_way' gespeichert werden.
Wird ein korrektes Ergebnis gefunden, wird eine Methode aufgerufen, die 'act_way' via addAll in 'opt_way' kopiert/speichert. In meiner Beispielrechnung wird nur einmal ein solches Ergebnis gefunden, die Methode wird korrekterweise auch nur einmal aufgerufen (nachgeprüft) und erfolgreich kopiert!

Die Berechnungen gehen danach weiter, weil durchaus noch ein besseres Ergebnis gefunden werden könnte und somit ändert sich auch weiterhin 'act_way'!
ABER... mit jeder Änderung von 'act_way' ändert sich ebenfalls 'opt_way'! :|

Wie ist denn das bitte schön möglich? Es wirkt fast so, als ob bei addAll lediglich ein Zeiger von 'act_way' auf 'opt_way' gelegt werden würde.


Update:
Habe vorhin das Problem noch etwas einkreisen können, allerdings sehe ich nach wie vor keinerlei Fehler und bleibe ratlos.


public void findWay(ArrayList act_way, WayCosts act_costs) {

Coords dummy = new Coords();

for(i = j; i < j+8; i++) {
dummy.assign(act_coords);
//bewege aktuelle Koordinate in eine der acht Himmelsrichtungen (Nordosten, Norden, Nordwesten, Westen, ...)
dummy.move(direction[i%8]);

if(..) {
if(..) {
act_way.add(dummy);
findWay(act_way, act_costs);
act_way.remove(act_way.size()-1);
}
}
}
}

Der Wert 'dummy' (im Code fett gedruckt) wird an die ArrayList 'act_way' dran gehängt, die später - wenn die Berechnung zu einem Ziel führte - von 'opt_way' übernommen wird.
Danach geht die Berechnung weiter (die for-Schleife in der achten Zeile wird zu Ende geführt) und somit ändert sich wieder 'dummy'...

'opt_way' hat zum Schluss jeweils den Wert, den 'dummy' am Ende der for-Schleife angenommen hat und nicht die Werte, die mit 'act_way' übergeben wurden. :|

Monger
2005-11-22, 09:18:43
Wie ist denn das bitte schön möglich? Es wirkt fast so, als ob bei addAll lediglich ein Zeiger von 'act_way' auf 'opt_way' gelegt werden würde.


Du hast das Problem hundertprozentig richtig erkannt: Deine Listen enthalten nur Referenzen auf Objekte. Alles was du machst ist, Referenzen zu kopieren.

Das ist eine wichtige (wenn nicht die wichtigste) Java Lektion: ALLES wird referenziert, ausser Basisdatentypen. Objekte im Speicher zu duplizieren, ist meistens alles andere als trivial, und ganz bestimmt nicht eindeutig.

Was du willst ist, eine KOPIE von Dummy in der anderen Liste zu referenzieren. Üblicherweise legt man eine Objektkopie über den Konstruktor an.
Zum Beispiel (Jetzt ohne Garantie, hab die API grade nicht vor mir!):

Coords newDummy = new Coords(dummy);

mithrandir
2005-11-22, 09:48:22
hm... Ist es nicht üblicher für Objekt-Kopien das Cloneable-Interface zu verwenden?

Senior Sanchez
2005-11-22, 11:08:15
hm... Ist es nicht üblicher für Objekt-Kopien das Cloneable-Interface zu verwenden?

Joar, eigentlich schon, also das ganze danach dann über .clone() abzuwickeln.

Monger
2005-11-22, 12:10:47
Joar, eigentlich schon, also das ganze danach dann über .clone() abzuwickeln.

clone() ist afaik immer untypisiert. Das heißt, man muss immer casten. Hässlich.

Außerdem ist nicht hundertprozentig klar, was das cloneable Interface macht. clone() zu überschreiben ist zwar empfohlen (und sinnvoll), aber nicht Pflicht. Und ist der Klon einer Liste nur eine Kopie der Liste, oder auch aller Einträge?


Ich finde, da ist die Verwendung des Konstruktors wesentlich eindeutiger, und viele Klassen im JDK unterstützen das ja auch.

Senior Sanchez
2005-11-22, 12:16:51
clone() ist afaik immer untypisiert. Das heißt, man muss immer casten. Hässlich.

Außerdem ist nicht hundertprozentig klar, was das cloneable Interface macht. clone() zu überschreiben ist zwar empfohlen (und sinnvoll), aber nicht Pflicht. Und ist der Klon einer Liste nur eine Kopie der Liste, oder auch aller Einträge?


Ich finde, da ist die Verwendung des Konstruktors wesentlich eindeutiger, und viele Klassen im JDK unterstützen das ja auch.

Hmm, ok, das ist wirklich nicht immer klar, ob es jetzt flache oder tiefe Kopien sind.

Bezüglich des untypisierten clone(), vllt wird das noch irgendwie geändert.

registrierter Gast
2005-11-22, 16:38:55
Du hast das Problem hundertprozentig richtig erkannt: Deine Listen enthalten nur Referenzen auf Objekte. Alles was du machst ist, Referenzen zu kopieren.

Das ist eine wichtige (wenn nicht die wichtigste) Java Lektion: ALLES wird referenziert, ausser Basisdatentypen. Objekte im Speicher zu duplizieren, ist meistens alles andere als trivial, und ganz bestimmt nicht eindeutig.

Was du willst ist, eine KOPIE von Dummy in der anderen Liste zu referenzieren. Üblicherweise legt man eine Objektkopie über den Konstruktor an.
Zum Beispiel (Jetzt ohne Garantie, hab die API grade nicht vor mir!):

Coords newDummy = new Coords(dummy);Thx, hat geklappt. :up: Allerdings mußte ich damit auf addAll verzichten und jede Koordinate einzeln adden. Geschwindigkeitseinbußen gab's dadurch aber anscheinend keine (105.5sec zu 105.7sec => Messungenauigkeiten). :smile:

HellHorse
2005-11-25, 23:15:56
Bezüglich des untypisierten clone(), vllt wird das noch irgendwie geändert.
Ziemlich sicher nicht. Denks mal durch. Das sind halt eben so Probleme mit statischen Typsystemen die alle hier so loben.

Senior Sanchez
2005-11-26, 00:29:19
Ziemlich sicher nicht. Denks mal durch. Das sind halt eben so Probleme mit statischen Typsystemen die alle hier so loben.

Kannste es mal näher erläutern, wie de das meinst?

HellHorse
2005-11-26, 13:38:07
Kannste es mal näher erläutern, wie de das meinst?
Es war etwas spät.
Mit Java 1.5 gibt es ja endlich kovariante Rückgabetypen. D.h. du könntest folgendes schreiben.

public class String implements ...., Clonable {
public String clone() {
return new String(this);
}
}


String s = "hallo".clone();

Das Problem hier ist dass man niemanden dazu zwingen kann kovariante Rückgabetypen zu verweneden.
Ok es geht schon, aber nur einmal. Das ist das berüchtigte Enum<E extends Enum<E>>.

Das würde dann etwa so aussehen.

public class A <C extends A<C>> {
public C clone() {
}
}

public class B extends A<B> {
public B clone() {
}
}

Schon verwirrt? Das ist wirklich ein Paradebeispiel gegen statische Typsysteme.

P.S.:
Man hat schon an einigen Orten explizit Hacks eingebaut (#getClass()) aber dass das für clone() auch gemacht wird glaube ich eher weniger, da es in der Praxis kaum gebraucht wird. Obwohl es in Object ist, kann man ja nie wissen, ob es wirklich funktioniert). Allerdings hat man in der letzten Zeit sehr viele achtjährige Bugs gefixt, von dem her ....

Senior Sanchez
2005-11-27, 17:42:37
Es war etwas spät.
Mit Java 1.5 gibt es ja endlich kovariante Rückgabetypen. D.h. du könntest folgendes schreiben.

public class String implements ...., Clonable {
public String clone() {
return new String(this);
}
}


String s = "hallo".clone();

Das Problem hier ist dass man niemanden dazu zwingen kann kovariante Rückgabetypen zu verweneden.
Ok es geht schon, aber nur einmal. Das ist das berüchtigte Enum<E extends Enum<E>>.

Das würde dann etwa so aussehen.

public class A <C extends A<C>> {
public C clone() {
}
}

public class B extends A<B> {
public B clone() {
}
}

Schon verwirrt? Das ist wirklich ein Paradebeispiel gegen statische Typsysteme.

P.S.:
Man hat schon an einigen Orten explizit Hacks eingebaut (#getClass()) aber dass das für clone() auch gemacht wird glaube ich eher weniger, da es in der Praxis kaum gebraucht wird. Obwohl es in Object ist, kann man ja nie wissen, ob es wirklich funktioniert). Allerdings hat man in der letzten Zeit sehr viele achtjährige Bugs gefixt, von dem her ....


Ok, danke für die Erläuterungen :)

Monger
2005-11-27, 19:14:03
Schon verwirrt? Das ist wirklich ein Paradebeispiel gegen statische Typsysteme.

Das ist jetzt vielleicht ein wenig sehr gesponnen, aber: ist das nicht im Grunde "nur" eine Schwäche der Sprache? Ich denke trotzallem dass Typisierung der richtige Weg ist um eine Sprache komfortabler und mächtiger zu machen. In Java gibt es halt noch kein ausgereiftes Sprachkonstrukt um Objekte (und alle Abhängigkeiten) richtig zu typisieren.

Trap
2005-11-27, 19:27:54
Alle Programmierprachen sind typisiert. Wie es gemacht wird ist wichtig.
-dynamisch/statisch
-explizit/implizit
-streng/schwach

Dann gibt es noch die ganzen Details die sich durch OOP ergeben:
-Rückgabewerte kovariant/contravariant/invariant
-Parameter genauso
-Polymorphie vs. Overloading
-single-dispatch vs. multi-dispatch

Java macht bei allen möglichen Entscheidungen genau das Gegenteil von dem was ich mir wünsche.

HellHorse
2005-11-27, 20:15:17
Das ist jetzt vielleicht ein wenig sehr gesponnen, aber: ist das nicht im Grunde "nur" eine Schwäche der Sprache?
Es ist ein Schwäche des Typsystems von Java. Zeig mir eines (statisch) in dem es geht, und beweise doch noch mal schnell das es `sound and complete' ist.

Ich denke trotzallem dass Typisierung der richtige Weg ist um eine Sprache komfortabler und mächtiger zu machen.
Ein statisches Typsystem schränkt den Programmier ein und ladet ihm zusätzliche Arbeit auf. Es macht also nichts komfortabler oder mächtiger. Es verhindert dass gewisser Code compiliert. Die Annahme ist, dass mehr sinnloser als sinnvoller Code zurückgewiesen wird.

HellHorse
2005-11-27, 20:28:28
-Polymorphie vs. Overloading

Polymorphie bezeichnet eigentlich die Fähigkeit einer Variablen Werte verschiedener Typen zu haben. Das hat nichts mit OOP zu tun und steht nicht in Konkurrenz zu Overloading. Was der Volksmund im Allgemeinen mit Polymorphie meint ist late-binding.

Unter starker/strenger Typisierung verstehet jeder etwas anderes (worin fällt C++).
Was vielleicht in der Liste noch fehlt ist coercion.

Coda
2005-11-27, 20:36:38
worin fällt C++Äh ohne dumme Casts ganz klar streng typisiert.

Trap
2005-11-28, 00:33:23
Polymorphie bezeichnet eigentlich die Fähigkeit einer Variablen Werte verschiedener Typen zu haben. Das hat nichts mit OOP zu tun und steht nicht in Konkurrenz zu Overloading.
Wie funktioniert Polymorphie ohne OOP in statisch typisierten Sprachen?

Ich empfinde es so als richtig:
monomorphe Variablen => overloading
polymorphe Variablen => multi-dispatch

Polymorphe Variablen mit overloading halte ich für verwirrend/kompliert und nicht besonders nützlich.

Noch zu single-dispatch vs. multi-dispatch:
Single-dispatch hat einige schöne Eigenschaften: man kann alle Methoden eindeutig einer Klasse zuordnen, man kann Klassen einzeln betrachten, spezifizieren und verifizieren. Außerdem ist es einfach performant zu implementieren.
Mit multi-dispatch kann man dafür Interaktionen zwischen mehreren gleichwertigen/gleichberechtigten Objekten sauber modellieren.

Monger
2005-11-28, 08:50:31
Das geht mir jetzt eine Spur zu schnell. Könntet ihr mir ein paar Begriffe erklären?

Polymorphie: ist doch die Fähigkeit eines Objektes, mehr als nur die Rolle eines einzigen Typs einnehmen zu können. z.B. eine Katze ist nicht nur ein Haustier, sondern auch ein Säugetier.

Overloading /überladen: Überschreibt Verhaltensweisen (=Methoden) von Objekten. Sinn der Geschichte ist, ein flexibleres Verhalten innerhalb bestimmter Grenzen zuzulassen. Z.B. jedes Auto kann hupen, aber jedes hört sich anders an.

Mit Single Dispatch /Multi Dispatch kann ich aber rein gar nichts anfangen.

HellHorse
2005-11-28, 09:30:14
Äh ohne dumme Casts ganz klar streng typisiert.
Was nichts anderes heisst als `Wenn C++ streng typisiert wäre, dann wäre es streng typisiert'. Klassische Nullaussage. Damit kommst du in keiner Prüfung durch ;)

Trap
2005-11-28, 09:30:30
Polymorphie ist oben schon richtig erklärt.

Overloading ist wenn man mehrere Methoden mit gleichem Namen hat und der Compiler anhand der deklarierten Typen der Argumente die Methode wählt die aufgerufen wird.

Multi-dispatch ist wie overloading nur dass es anhand der tatsächlichen Typen der Argumente die Methode wählt.

Single-dispatch ist das was Java macht, es wird in x.m(y,z) nach dem dynamischen Typ von x unterschieden welches m aufgerufen wird.

HellHorse
2005-11-28, 09:44:31
Wie funktioniert Polymorphie ohne OOP in statisch typisierten Sprachen?
Java als besseres C?

Monger
2005-11-28, 10:29:28
Single-dispatch ist das was Java macht, es wird in x.m(y,z) nach dem dynamischen Typ von x unterschieden welches m aufgerufen wird.

Nur damit mir das 100%ig klar wird: Java führt doch immer genau die Methode aus, die ursprünglich zu dem Objekt gehört, oder?

Das heißt, wenn ich ein Objekt vom Typ "Katze" erstelle, wird jede Methode die ich darauf ausführe auch tatsächlich aus der Klasse "Katze" stammen, selbst wenn meine Katze gerade mal als Haustier, Säugetier oder Tier deklariert ist.

Senior Sanchez
2005-11-28, 10:31:33
Das heißt, wenn ich ein Objekt vom Typ "Katze" erstelle, wird jede Methode die ich darauf ausführe auch tatsächlich aus der Klasse "Katze" stammen, selbst wenn meine Katze gerade mal als Haustier, Säugetier oder Tier deklariert ist.

So sieht das aus. Es wird immer die Methode ausgeführt, die in der Hierarchie am nächsten ist, sprich zuerst aus Katze, dann aus Haustier etc. halt solange bis er eine findet.

zeckensack
2005-11-28, 12:22:04
Wie funktioniert Polymorphie ohne OOP in statisch typisierten Sprachen?

Ich empfinde es so als richtig:
monomorphe Variablen => overloading
polymorphe Variablen => multi-dispatch

Polymorphe Variablen mit overloading halte ich für verwirrend/kompliert und nicht besonders nützlich.Rhetorische Frage?
1)IMO kann man overloading schon in Polymorphie einsortieren, bzw man sollte zumindest anerkennen dass es ein nützliches Werkzeug ist um Polymorphie in Sprachen abzubilden die keine OOP haben.
(ist eher theoretisch, weil zB C++ beides könnte, nacktes C aber kein Overloading hat)

2)Funktionszeiger.

Trap
2005-11-28, 18:52:10
@Zeckensack & Hellhorse:
Die Frage nach den polymorphen Variable ohne OOP ist ernst gemeint.

Overloading hat mit Polymorphie garnichts zu tun, Funktionszeiger auch nicht. Mit Funktionszeigern kann man OOP ohne Polymorphie machen, aber ich wollte es umgekehrt herum wissen (Polymorphie ohne OOP).

Ohne Vererbung ist nix mit Polymorphie in den Sprachmodellen die ich kenne und Vererbung gehört für mich eindeutig zu OOP.

zeckensack
2005-11-28, 20:00:43
@Zeckensack & Hellhorse:
Die Frage nach den polymorphen Variable ohne OOP ist ernst gemeint.

Overloading hat mit Polymorphie garnichts zu tun,Kommt darauf an was man unter Polymorphie versteht ... ich hab nochmal drüber nachgedacht und habe dich wahrscheinlich falsch verstanden.
Ich hatte mir das so gedacht:typedef float KreisRadius;
typedef float QuadratKantenLaenge;

float
volumen(KreisRadius kr)
{
return(quadratpiblah);
}

float
volumen(QuadratKantenLaenge)
{
return(quadratblah);
}Die beiden Typen kann man natürlich nicht in einen gemeinsamen Container schmeißen und darauf hoffen dass es noch funktioniert. Die Typen müssen beim Kompilieren bekannt sein, denn beim Kompilieren werden auch schon die Overloads aufgelöst. Insofern dann doch keine Polymorphie.
Funktionszeiger auch nicht. Mit Funktionszeigern kann man OOP ohne Polymorphie machen, aber ich wollte es umgekehrt herum wissen (Polymorphie ohne OOP).typedef float (*volumen_fp)(float);

float
kreis_volumen(float radius)
{
return(quadratpiblah);
}

float
quadrat_volumen(float kantenlaenge)
{
return(quadratblah);
}

volumen_fp volumen[2];
float daten[2];

int
main()
{
volumen[0]=&quadrat_volumen;
daten[0]=5.0f;
volumen[1]=&kreis_volumen;
daten[1]=5.0f;

for (int i=0;i<2;++i)
{
float v=volumen[i](daten[i]);
...
}
return(0);
}Das Beispiel wäre schöner wenn man structs nutzen würde. Es soll nur zeigen dass es auch ohne geht, nicht dass mir jemand noch vorwirft eine struct wäre eine verkappte Klasse, und ich hätte geschummelt :)

Kann man natürlich um beliebig viele "Member-Funktionen" und "Member-Variablen" erweitern. Es müssen nur alle "Klassen" das gleiche "Interface" implementieren, und die "Instanz"-Daten müssen von Anzahl und Typ übereinstimmen (man kann zur Not einige ungenutzt lassen). Auch um diese Einschränkungen kommt man herum, aber dann wird's langsam hässlich.

Die ganz harten pfeifen auf Funktionszeiger und nehmen sowas:typedef unsigned int ObjectType;

void
do_stuff(ObjectType t,float object_data[])
{
switch(t)
{
...
}
}Ohne Vererbung ist nix mit Polymorphie in den Sprachmodellen die ich kenne und Vererbung gehört für mich eindeutig zu OOP.In meinem kruden Beispiel oben erben beide "Klassen" ein gemeinsames "Interface". Zählt das nicht? Bzw was meinst du genau?
(Beispiele willkommen)

Trap
2005-11-28, 21:18:31
So, jetzt weiß ich selbst nichtmehr was ich eigentlich meine. Ich bin eigentlich von der Definition ganz oben ausgegangen: Eine Variable ist polymorph wenn sie Werte aus unterschiedlichen Typen annehmen kann.

Wobei wir damit das Problem nur verschoben haben auf die Frage "Was bedeutet unterschiedlich bezogen auf Typen?". Ich benutze es so: 2 Typen sind unterschiedlich wenn "Typ1 varname = Wert2" und "Typ2 varname = Wert1" beide nicht erlaubt sind.

In deinem Beispiel kommt sowas nicht vor, da sind nur Variablen vom Typ Funktion float->float, floats und ints und eine Variable enthält immer Werte von genau 1 Typ.

In OOP Programmen enthalten Variablen dagegen oft Werte mit eindeutig verschiedenen Typen (natürlich nacheinander, nicht auf einmal):
GeometricObject x = new Sphere();
x = new AABB();

Daher meine Frage wie Polymorphie in statisch typisierten Programmiersprachen aussehen soll, wenn sie nicht durch Vererbung erreicht wird. Ok, void* sind polymorph, die sind aber nicht typisiert...

HellHorse
2005-11-28, 21:45:39
@Zeckensack & Hellhorse:
Die Frage nach den polymorphen Variable ohne OOP ist ernst gemeint.
Die Antwort auch. Schau dir Klassen einfach als structs an.

Overloading hat mit Polymorphie garnichts zu tun,
ACK

Ohne Vererbung ist nix mit Polymorphie in den Sprachmodellen die ich kenne
In statischen Typsystemen? Interfaces in Java oder sind wir schon wieder von OOP weg?

Dummerweise ist mein Wissen über statische Typsysteme ausserhalb des Mainstream auch sehr dürftig. :(

Das heißt, wenn ich ein Objekt vom Typ "Katze" erstelle, wird jede Methode die ich darauf ausführe auch tatsächlich aus der Klasse "Katze" stammen, selbst wenn meine Katze gerade mal als Haustier, Säugetier oder Tier deklariert ist.
Nein, private und static Methoden sind statisch gebunden. Bei package protected weiss ich es nicht, aber ich vermute mal nicht.

P.S.:
Scheisse, wieder so ein an und für sich harmloser Thread der völlig ausser Rand und Band ist, und ich bin mitschlud. Aber wenigstens kein bashing ;)

zeckensack
2005-11-28, 23:39:09
So, jetzt weiß ich selbst nichtmehr was ich eigentlich meine. Ich bin eigentlich von der Definition ganz oben ausgegangen: Eine Variable ist polymorph wenn sie Werte aus unterschiedlichen Typen annehmen kann.

Wobei wir damit das Problem nur verschoben haben auf die Frage "Was bedeutet unterschiedlich bezogen auf Typen?". Ich benutze es so: 2 Typen sind unterschiedlich wenn "Typ1 varname = Wert2" und "Typ2 varname = Wert1" beide nicht erlaubt sind.Das ist gemein. Dafür bräuchte man schon Overloads und/oder structs. Wenn du mir structs verbietest, komme ich mit einer einzelnen Zuweisung nicht aus (ein Funktionsaufruf oder eine "inline"-Lösung werden nötig). Wenn du mir Overloads verbietest, kann ich nicht selektiv Zuweisungen erlauben oder nicht erlauben.
In deinem Beispiel kommt sowas nicht vor, da sind nur Variablen vom Typ Funktion float->float, floats und ints und eine Variable enthält immer Werte von genau 1 Typ.Mein Beispiel kann man in der Pfeife rauchen, oder auch erweitern. Mit Typen und Subtypen, unterschiedlichen Anzahlen, Typen und Bedeutungen von "Member"-Variablen, und ganz ohne Casts:struct
Object
{
int type; //1 für Essen, 2 für Trinken, 3 für Haustiere, 4 für ...

float* float_data;
int* int_data;
}

const int HAUSTIER_SUB_KATZE=0;
const int HAUSTIER_SUB_HUND=1;

const int FARBE_WEISS=0;
const int FARBE_SCHWARZ=1;
const int FARBE_DRECKIG=2;
...

void
init_katze(Object* o)
{
o->type=3;
o->float_data=0; //woll'n wir nicht
o->int_data=new int[5];
o->int_data[0]=HAUSTIER_SUB_KATZE;
o->int_data[1]=4; //Anzahl der Beine
o->int_data[2]=1; //Anzahl der Köpfe
o->int_data[3]=FARBE_SCHWARZ; //Farbe
o->int_data[4]=1; //ist (noch) wach
}

void
init_erbsensuppe(Object* o)
{
o->type=1;
o->int_data=0; //nyx
o->float_data=new float[2];
o->float_data[0]=0.5f; //Viskosität
o->float_data[1]=12.5f; //Temperatur
}

void
steh_rum(Object* o)
{
switch(o->type)
{
case(1): //Essen
o->float_data[1]-=1.0f; //kälter werden
break;
case(3): //Haustier
if ((rand()&255)<4) einschlafen(o); //müde werden
break;
default:
cout << "Nein!";
break;
}
}

void
sag_hallo(Object* o)
{
switch(o->type)
{
case(3): //Haustier
if (o->int_data[0]==HAUSTIER_SUB_KATZE) cout << "*hust*";
else
if (o->int_data[0]==HAUSTIER_SUB_HUND) cout << "*bell*";
else cout << "Muss ich noch lernen";
break;
default:
cout << "Kann ich nicht";
break;
}
}

void
fliess_herum(Object* o)
{
switch(o->type)
{
case(1): //Essen
if ((o->float_data[0]>0.1f)&&(o->float_data[1]>4.0f)) cout << "*schwapp*"; //ist flüssig und nicht eingefroren
break;
case(3): //Haustier
if (o->int_data[4]!=0) cout << "*blödguck*"; //ist überfordert
else cout << "*schnarch*"; //schläft sowieso schon
break;
default:
cout << "Nein!";
break;
}
}


int
main()
{
Object A,B;
init_katze(&A);
init_erbsensuppe(&B);
...
return(0);
}Und das ginge auch mit Funktionszeigern ...
Du musst doch nur erreichen dass die "Member"-Funktionen das richtige machen, und das falsche (zB Zugriff auf in diesem Typen nicht vorhandene Daten) nicht machen. Dafür kannst du entweder den Typ irgendwie die Objekte reinkodieren (wie Object.type oben), oder eben Funktionszeiger nehmen, oder irgendwas dazwischen.
C++-Compiler implementieren polymorphes Gedöns idR mit einem Zeiger auf ein Array auf Funktionszeiger. Der erste Zeiger wird in der Instanz gespeichert. Auch das kann man zu Fuß haben, ohne jemals einen Typen umwandeln zu müssen.

Monger
2005-11-29, 08:53:35
...
Nein, private und static Methoden sind statisch gebunden. Bei package protected weiss ich es nicht, aber ich vermute mal nicht.


??? Ich versteh nicht was du meinst! private kann ja ohnehin nicht vererbt werden, insofern fällt auch Single-Dispatch flach. Und bei Klassenattributen (eben static) gibt es ja ohnehin keine Polymorphie, oder wie soll das aussehen ?!?

Wobei...
Ein Haustier kann natürlich eine private Methode mit genau der selben Signatur wie eine Katze haben. Aber sie wird nicht überschrieben, weil eine Katze ja ohnehin nichts von den private Methoden der Oberklassen weiß...

Insofern hinkt der Vergleich.

HellHorse
2005-11-29, 19:06:00
??? Ich versteh nicht was du meinst! private kann ja ohnehin nicht vererbt werden,
Doch natürlich. Sie sind bloss staisch gebunden, das ist alles.

class A {
public void makeSayHello(A a) {
a.sayHello();
}


private void sayHello() {
System.out.println("A");
}
}
class B extends A {
private void sayHello() {
System.out.println("B");
}

public static void main(String[] args) {
A a = new A();
B b = new B();
a.makeSayHello(b);
}
}


Und bei Klassenattributen (eben static) gibt es ja ohnehin keine Polymorphie, oder wie soll das aussehen ?!?
Es ging nicht um Attribute sondern Methoden. Die gleiche Lookup-Semantik wie auf der Instanzseite ist problemlos auf der Klassenseite möglich.