Anfängerfrage zu Java
-
@designpattern
Wieso soll das ein übler Hack sein? Und wie würde deiner Meinung nach ein solches Design aussehen? Und vor ALLEM, wie löse ich diese Situation nun in Java?
-
Schreibst du das gerade oder möchtest du etwas bestehendes nach Java konvertieren?
Worin unterscheidet sich die erste und zweite Klasse? Beide geben einen Punkt an, sofern es sich um einen Ortsvektor handelt.designpattern schrieb:
ein klares design wäre eine möglichkeit um solche üblen hacks zu vermeiden - auch in c++
Egal um was es sich handelt, du benötigst ja nur die Punkt bzw. Eckpunkte. Besorg dir dies mit
- einem Iterator
- einem Array
- was weiß ichinterface 3DBody { Iterator<Point> getEdgeIterator() Array<Point> getEdgePointsAsArray() } BoundingSphere.createFrom(Iterator<Point> it) { .... } // oder BoundingSphere.createFrom(Array<Point> ar) { .... }
-
@Siassei
Deine beiden Vorschläge setzen voraus, dass sich die Daten noninterleaved im Speicher befinden. Die Funktion soll aber mit interleaved sowie auch mit noninterleaved Daten umgehen können.
-
Ähmm, kennst du die Bedeutung deiner Wortwahl? Ich musste nachschauen
Wer sagt denn, dass die Daten geordnet im Speicher liegen müssen?
z.B. Ein Iterator muss die Daten ja nicht mit der Vorschrift
i_first = 0
i_neu = i_alt + 1
i_end = array.size-1
durchlaufen.
Ehrlich gesagt erfüllen meine Vorschläge deine Forderungen von deinem ersten Post.
-
@Siassei
Hehe, ok, ich weis was du meinst. Es würde halt bedeuten, dass ich eine Klasse schreiben müsste, welche ein Interface (in deinem Beipiel 3DBody) implementiert und die Daten ausliest. Das würde sicherlich funktionieren, da gebe ich dir recht, aber ist das nicht ein bisschen viel Mehraufwand? Eine ganze Klasse (Java) gegen einen einzigen Paramter (C++)?Wegen dem Interleaved vs. Noninterleaved:
// noninterleaved
Array<Vector3> aPos;
Array<Color> aClr;// interleaved
struct Interleaved{
Vector3 Pos;
Color Clr;
};
Array<Interleaved> aInt;Es bedeutet im Kontext von Memoryalignment, dass sich die Daten "versetzt" im Speicher befinden. Bei Bilder muss man bspw. diese Unterscheidung machen: Kommen zuerst alle rot werte, anschliessend alle grün werte und am schluss alle blau werte oder kommt rot grün blau rot grün blau rot grün blau für jeden Pixel. Oder auch bei 3D Formaten: Kommen zuerst alle Positionsvektoren gefolgt von allen Normalen oder kommt Position, Normale, Position, Normale usw...
Bei der Kommunikation von unterschiedlichen Bibliotheken kann es durchaus vorkommen, dass die Daten (transformiert) werden müssen. Aber ich sehe da nun eine einfache Addition (C++) gegen einen ganzen virtuellen Funktionsaufruf in (Java). Bei Millionen von Punkten kann dies sehr schnell deutlich in die Performance gehen, besondern wenn diese Daten mehrere 100 Male pro Sekunden transformiert werden müssen. Daher frage ich, gibt es da nicht einen einfacheren / eleganteren Weg als eigens dafür eine ganze Adapterklasse schreiben zu müssen?
-
Ishildur schrieb:
Daher frage ich, gibt es da nicht einen einfacheren / eleganteren Weg als eigens dafür eine ganze Adapterklasse schreiben zu müssen?
Ich möchte dir nicht zu nahe treten, aber derartige Gedanken im voraus Behindern nur die Arbeit. Sicherlich ist es nicht schlecht um vorhinein abzuwägen, was wohl besser wäre. Aber da liegt man oft weit daneben.
Meist geht bei Vorüberlegungen mehr Zeit verloren, als bei gezielten Optimierungen am Ende.Ich persönlich rate immer dazu, zuerst ein gutes Design + eine gute Struktur aufzubauen.
Erst später, bei den ersten Testläufen, wird ermittelt was wirklich zu lange dauert und optimiert.
Übrigends sind in Java alle Methoden virtual definiert. Aber das macht nichts. Der JIT'ler erzeugt den Code, der ausgeführt wird, erst zur Laufzeit. Hier wird entschieden, ob er die Methode inlined oder ... . Bei Methoden von x-Zeilen (x < eine bestimte Größe) passiert das automatisch.Du kannst auch in Java folgendes Schreiben
void createAbc1(Point[] data, int first, int last, int offset) { //.... ... = data[first + i *offset] //.... } // offset is powerOfTwo void createAbc2(Point[] data, int first, int last, int offset) { //.... ... = data[first + (i << offset)] //.... }
Der Compiler von Sun optimiert bei createAbc1 das ganze. Im Hintergrund entspricht das den Zeiger-Operation in C++.
Sun rät trotzdem davon ab. Eine zusätzliche Klasse bietet viel mehr Möglichkeiten und ist leichter lesbar. Der angesprochene Iterator kann Beispielsweise auch an einer anderen Stelle verwendet werden. z.B. bei QuaderBounding. Änderungen an der Datenstruktur lassen sich besser durchführen. ...Also nicht vergessen. Zuerst alles sauber umsetzen und danach gezielt optimieren. Und achja, rufe niemals den GC manuell auf.
-
Diese Methode funktioniert nun aber nur mit Point Arrays? (Wieder noninterleaved)
P.S.
Du tritts mir schon nicht zu nahe, keine Angst! Ich empfinde Ratschläge als Bereicherung und nicht als Bedrohung
-
T[] data
-
Nimm mal ein OOP Buch in die Hand (Ob C++ oder Java ist egal). Wer solchen Code wie den Beispiel-C++-code von oben schreibt gehört IMO erstmal wieder in den 9. Klasse Informatikunterricht. So ein Perverso-Code wie da oben ist übrigens auch einer der Gründe warum C++ bei vielen so unbeliebt ist - obwohl es ein Problem des Programmierers und nicht der Sprache ist...
-
@sarrazin
Genau: "Ich verstehe es nicht, darum ist es böööse!"Ich habe mich während meinem Studium intensiv mit Software Archituktur, Design & Patterns und OO beschäftigt. Allerdings ebenso mit Algorihmen und Datenstrukturen sowie unter vielem Anderem mit dem (hierfür relevanten) Laufzeitverhalten von statischem vs. dynamischem Polymorphismus sowie mit Cache Hit Rates. Was glaubst du wohl, was effizienter ist: Der Aufruf eines virtuellen Enumerators / Iterators oder eine simple Pointerarithmetik (im selben Cache Block) für einige 100 Millionen Verticen pro Sekunde? Schau dir doch diesbezüglich auch mal das Dissasembly sowie die Architektur des L1 und l2 Caches gerade auf Multicore Prozessoren an.
Das dürfte dich auch interessieren:
Gerade die generische Programmierung macht C++ zu einem mächtigen Programmierwerkzeug. Während die objektorientierte Programmierung in Java und C# nach wie vor den zentralen Abstraktionsmechanismus darstellt, ist diese Art der Programmierung in C++ rückläufig. So werden tiefe Klassenhierarchien vermieden, und zu Gunsten der Effizienz und der Minimierung des Ressourcenverbrauchs verzichtet man in vielen Fällen auf Polymorphie, einen der fundamentalen Bestandteile der objektorientierten Programmierung.
Findest du unter Wikipedia
Der Grund für die angebliche "Unbeliebtheit" von SYSTEMnahen Sprachen wie C++ ist vielmehr die Tatsache, dass hierfür eine gewisse Kenntnis des SYSTEMs (wie bpsw. Speicherbereiche wie BSS, Stack u. Heap, Addressierungs Schmemas, User vs. Kernelmode, Cache Architekturen, DMA Contraints, Memory Alignment uvm.) erforderlich sind, um effizient entwickeln zu können.
Zu einer sachlichen Diskussion oder Auseinandersetzung mit der Thematik wäre ich gerne bereit gewesen. Auf dieses "DU HAST KEINE AHNUNG, GEH NOCH MAL IN DIE 9. KLASSE..." Geschrei habe ich hingegen ganz ehrlich überhaupt keine Lust und darum belassen wir es denke ich besser dabei.
Ich bin dann mal weg...
-
Ich würde es ungefähr so lösen (denke, es ist ähnlich zu Siasseis Ansatz):
public interface PointIterator { boolean next(double[] data); } public abstract class AbstractPointIterator implements PointIterator { private double[] data; private int pointSize; private int count; private int pos; public AbstractPointIterator(double[] data, int pointSize) { this.data = data; this.pointSize = pointSize; this.count = data.length / pointSize; this.pos = 0; } public boolean next(double[] output) { if (pos < count) { createPoint(data, output, count, pointSize, pos); pos++; return true; } return false; } protected abstract void createPoint(double[] data, double[] output, int count, int pointSize, int pos); } public class InterleavedPointIterator extends AbstractPointIterator { public InterleavedPointIterator(double[] data, int pointSize) { super(data, pointSize); } @Override protected void createPoint(double[] data, double[] output, int count, int pointSize, int pos) { for (int i = 0; i < pointSize; i++) { output[i] = data[pos * pointSize + i]; } } } public class NonInterleavedPointIterator extends AbstractPointIterator { public NonInterleavedPointIterator(double[] data, int pointSize) { super(data, pointSize); } @Override protected void createPoint(double[] data, double[] output, int count, int pointSize, int pos) { for (int i = 0; i < pointSize; i++) { output[i] = data[i * count + pos]; } } } public void calculate(double[] data, int pointSize, boolean interleaved) { PointIterator it = (interleaved) ? new InterleavedPointIterator(data, pointSize) : new NonInterleavedPointIterator(data, pointSize); double[] point = new double[pointSize]; while (it.next(point)) { // ... calculate with point } }
Augenmerk liegt dabei auf folgenden Punkten:
- Kein Speicherkopieren und keine neuen Objekte erstellen während berechnet wird
- Demonstration interleaved vs. non-interleaved
- Flexibel - kann genauso auch mit einer Liste von Points oder ähnlichem arbeiten
- Flexible Größe der Punkte - wenn die immer 3 ist, kann man das auch fest reinkodieren.
Um einen "echten" objektorientierten Ansatz wird man - wie auch schon erwähnt - bei Java nicht herumkommen.