Templates in Java



  • Es gibt Generics, die aber keine starken Ähnlichkeiten mit Templates haben. Der Hauptunterschied ist, dass sie keine Textersetzung darstellen, sondern Code, der verschiedene Typen lauffähig ist.

    ArrayList<String> stringList = new ArrayList<String>();
    

    Primitive Typen werden leider auf Grund der Art, wie die Generics realisiert worden sind, nicht unterstützt. In einigen Punkten sind sie jedoch auch sehr flexibel. Du kannst upper- und lower- Typebounds vorgeben, z.B.

    void <T>sort(T[], Comparator<? super T>)
    

    Du kannst dir ja mal http://java.sun.com/developer/technicalArticles/J2SE/generics/index.html durchlesen.



  • Vielen Dank für die schnellen Antworten 🙂 !!!

    Im konkreten Fall muß ich eine in C++ mit Templates codierte Funktion in Java umsetzen.
    Dieser Funktionsheader sieht so aus:

    template<class T> void 	Archive(T& ToAdd);
    

    Der Funktion können beliebige Datentypen, wie char, short oder double übergeben werden. Anhand des Typs, weiß die Funktion wieviel Bytes aus/in einem Bytestream gelesen/geschrieben werden sollen.
    Läßt sich so etwas in Java mit einer Funktion realisieren oder muß für jeden Datentyp eine neue Funktion geschrieben werden?
    So wie es aussieht kann ich dafür die Generics nicht verwenden.

    Danke nochmals!



  • Soll das sowas wie java.io.DataInputStream oder java.io.DataOutputStream werden?



  • Ja das soll so etwas wie DataInputStream und DataOutputStream sein. Nur, dass die Struktur etwas anders ist, Strings werden mit Archive z.B. mit 4 Bytes-Längenangabe gespeichert und bei den Zahlen werden die Bytes verdreht. Es ist wichtig, dass das mit Java erzeugt File, Bit für Bit die gleiche Struktur hat. Deswegen kann ioh diese Streams nicht nutzen.



  • dziuba schrieb:

    Nur, dass die Struktur etwas anders ist, Strings werden mit Archive z.B. mit 4 Bytes-Längenangabe gespeichert und bei den Zahlen werden die Bytes verdreht. Es ist wichtig, dass das mit Java erzeugt File, Bit für Bit die gleiche Struktur hat. Deswegen kann ioh diese Streams nicht nutzen.

    Und wie kommst du dann dadrauf, dass du das mit einem "Template" machen kannst? Offensichtlich mußt du ja jeden Datentyp anders behandeln. Bei den einen mußt du Bytes vertauschen, bei anderen mußt du die "Größe" verändern. Das wirst du weder mit Templates noch mit Generics hinkriegen. Da sind einfach unterschiedliche Methoden gefragt. Du kannst in Java aber natürlich eine Methode als so eine Art "Flaschenhals" definieren. Eine Methode, die alles annimmt und dann via Reflection prüft, welcher Typ vorliegt und an welche Methode das zur Weiterverarbeitung weitergereicht werden soll. ...mit der Einschränkung, dass du dann für die primitiven Typen die Wrapper benutzen mußt.



  • Gregor@Home schrieb:

    Und wie kommst du dann dadrauf, dass du das mit einem "Template" machen kannst? Offensichtlich mußt du ja jeden Datentyp anders behandeln.

    Zum Teil kann man da schon Templates benutzen. Klar für Strings, Vectoren und Zahlen muß man unterschiedliche Methoden schreiben. Aber man könnte mit Templates alle Zahlen von short bis long mit einer Methode behandeln. Unter C++ liest diese Methode zuerst anhand der übergebenen Datentyps mit sizeof(...) die Bytelänge des Typs. Mit der Bytelänge kann sie dann die bestimmte Anzahl von Bytes lesen, bzw. schreiben.



  • Warum serialisierst du nicht einfach eiskalt alles? Sieh dir mal den ObjectInputStream und den ObjectOutputStream an.



  • dziuba schrieb:

    Zum Teil kann man da schon Templates benutzen. Klar für Strings, Vectoren und Zahlen muß man unterschiedliche Methoden schreiben. Aber man könnte mit Templates alle Zahlen von short bis long mit einer Methode behandeln. Unter C++ liest diese Methode zuerst anhand der übergebenen Datentyps mit sizeof(...) die Bytelänge des Typs. Mit der Bytelänge kann sie dann die bestimmte Anzahl von Bytes lesen, bzw. schreiben.

    Aber die Länge der primitiven Datentypen ist doch in C++ gar nicht genau definiert? Es gibt AFAIK immer nur so eine Art Untergrenze. Das heißt, dass der Wert, den dir sizeof gibt, sowieso nicht mit mit der Schnittstelle dieses Archivs (oder was das ist) übereinstimmen muss. In Java stimmen die prmitiven Datentypen auch nicht unbedingt mit denen von c++ oder denen deines Archivs überein. Hier hast du sehr genau vorgegeben, wieviele Byte ein bestimmter Datentyp hat. Und während ein char in C++ normerlweise 8 Bit hat (ich weiß nicht, ob man sich darauf verlassen kann), hat er in Java 16 Bit.

    Naja, um mal wieder auf's Thema zurückzukommen: Du wirst in Java letztendlich separate Methoden schreiben müssen. Alleine schon deshalb, weil es in Java kein sizeof gibt. Oder du veranstaltest so eine Art if-Orgie in deiner einen Methode, in der du jeden Typ dann separat behandelst. Aber wenn du über eine einzige Methode gehen willst, dann kostet das natürlich entsprechend Performance. Du mußt die primitiven Typen dann wrappen und du mußt sie in der Methode wieder separat behandeln. Das hast du bei der Codegenerierung, die mit Templates in C++ verbunden sind, natürlich nicht. Da werden dir im Prinzip implizit unterschiedliche Methoden generiert, die natürlich nicht in deinem Quellcode auftauchen, sondern nur im Kompilat.



  • Du wirst in Java letztendlich separate Methoden schreiben müssen. Alleine schon deshalb, weil es in Java kein sizeof gibt.

    Was spricht jetzt gegen die Serialisierung mit ObjectOutputStream? Die geht doch für jeden Typ. Oder macht DataInputStream irgendwas tolles, was ich jetzt übersehen habe?



  • Optimizer schrieb:

    Was spricht jetzt gegen die Serialisierung mit ObjectOutputStream? Die geht doch für jeden Typ. Oder macht DataInputStream irgendwas tolles, was ich jetzt übersehen habe?

    Er muss sich offensichtlich einem ganz bestimmten externen Format für die Datentypen anpassen. Ich weiß jetzt nicht, ob man einen ObjectOutputStream entsprechend konfigurieren kann, dass er die Daten entsprechend formatiert. Wenn man das kann, dann ist das sicherlich die beste Lösung. Wenn man es nicht kann, dann kommt der nicht in Frage.



  • Optimizer schrieb:

    Primitive Typen werden leider auf Grund der Art, wie die Generics realisiert worden sind, nicht unterstützt. In einigen Punkten sind sie jedoch auch sehr flexibel. Du kannst upper- und lower- Typebounds vorgeben, z.B.

    dank auto(un)boxing kein problem:

    List<Integer> zahlen = new ArrayList<Integer>();
    zahlen.add(123);
    int zahl = zahlen.get(0);
    


  • Roar schrieb:

    dank auto(un)boxing kein problem:

    List<Integer> zahlen = new ArrayList<Integer>();
    zahlen.add(123);
    int zahl = zahlen.get(0);
    

    In jedem Bereich, in dem Performence oder auch Speicherverbrauch eine Rolle spielt, ist das keine akzeptable Lösung.



  • Optimizer schrieb:

    Was spricht jetzt gegen die Serialisierung mit ObjectOutputStream? Die geht doch für jeden Typ. Oder macht DataInputStream irgendwas tolles, was ich jetzt übersehen habe?

    Da hat Gregor@Home recht. Ich muß mich einem externen Format für Datentypen anpassen. Deswegen kann ich den ObjectOutputStream nicht benutzen. Ansonsten wäre er sehr komfortabel.

    Danke nochmal an alle für die hilfreichen Antworten. Ihr habt mir sehr geholfen!


Anmelden zum Antworten