1. Dashboard
  2. Forum
    1. Unerledigte Themen
  3. Mitglieder
    1. Letzte Aktivitäten
    2. Benutzer online
    3. Team-Mitglieder
    4. Trophäen
    5. Mitgliedersuche
  4. Tutorial Bereich
  • Deutsch
  • Anmelden
  • Registrieren
  • Suche
Dieses Thema
  1. Informatik Forum
  2. Webmaster & Internet
  3. Entwicklung

Generics

  • ComSubVie
  • 28. November 2006 um 13:40
  • Unerledigt
  • ComSubVie
    5
    ComSubVie
    Mitglied
    Punkte
    230
    Beiträge
    42
    • 28. November 2006 um 13:40
    • #1

    Wo Java doch Generics kann, sollte man diese doch auch nutzen. Aber irgendwie scheint die Umsetzung ein bisschen Pfusch zu sein...

    Also ich will in der Superklasse eine generische Funktion haben, damit ich das nicht in jeder Subklasse selbst implementieren muss. Diese Funktion konvertiert mir eine Liste in ein Generic Array (da sind dann aber natürlich noch ein paar andere Funktionen drin). Jedenfalls war das die Idee:

    Java
    import java.util.List;
    
    
    public class Manager<E> {
    
    
        public Manager() {
        }
    
    
        protected E[] convertListToArray( List list ) {
            E retVal[] = new E[list.size()];
            for ( int l = 0; l < list.size(); l++ ) {
                retVal[l] = (E)list.get( l );
            }
            return retVal;
        }
    
    }
    Alles anzeigen

    Und jetzt würde ich mir davon einfach ein paar Klassen bauen, die das verwenden, also z.B. "public class AddressManager extends Manager<Address>"

    Allerdings kompiliert mir die Manager Klasse nicht, weil "Cannot create generic array of E" sowie "The cast from Object to E is actually checking against the erased type Object". Aha. Warum?!?

    Außerdem würd ich auch gerne meine PersistenceManager Abfragen generalisieren, also

    Code
    public E[] getList() {
            Query query = em.createQuery( "SELECT c FROM " + E.class.getName() + " AS c" );
            List resultList = query.getResultList();
            return convertListToArray( resultList );
        }

    Allerdings will er ein E.class.getName() auch nicht "Illegal class literal for the type of parameter E".

    Irgendwelche Vorschläge wie ich Java trotzdem dazu bringen kann meinen Code zu fressen (bzw. mir viel Copy&Paste zu ersparen)?

  • a9bejo
    21
    a9bejo
    Mitglied
    Reaktionen
    42
    Punkte
    4.697
    Beiträge
    913
    • 28. November 2006 um 15:38
    • #2

    Das liegt an dem Type Erasure Process, der bei Java Generics zum Tragen kommt:

    Zitat


    When a generic type is instantiated, the compiler translates those types by a technique called type erasure — a process where the compiler removes all information related to type parameters and type arguments within a class or method. Type erasure enables Java applications that use generics to maintain binary compatibility with Java libraries and applications that were created before generics.

    Bruce Eckel hat das Thema Java Generics und type erasure mal sehr gruendlich dokumentiert:
    [ 1, 2, 3, 4 ]

    lg, Benjamin Ferrari, bookworm.at

  • ComSubVie
    5
    ComSubVie
    Mitglied
    Punkte
    230
    Beiträge
    42
    • 28. November 2006 um 19:31
    • #3

    Super, danke. Ich hab zwar schon recht viel von ihm gelesen, aber das ist mir bisher entgangen... Nochmal danke, das sollte ein bisschen helfen...

  • kubuntu
    6
    kubuntu
    Mitglied
    Reaktionen
    2
    Punkte
    352
    Beiträge
    65
    • 29. November 2006 um 13:26
    • #4

    Nachdems schon nen Generics Thread gibt, post ich gleich hier rein :) Folgender Code kompiliert bei mir unter Eclipse aber nicht mit javac:

    Code
    static <T,L extends AbstractCollection<T>> L filter(Predicate<T> pred, L list)
    {
        L v = createObject(list.getClass());
        for (T t: list) {
            if (pred.fn(t))
                v.add(t);
        }
        return v;
    }
    
    
    static <T> T createObject(Class<T> cl)
    {
        try {
            return cl.newInstance();
        } catch (InstantiationException e) {
            // err handling
        } catch (IllegalAccessException e) {
            // err handling
        }
        return null;
    }
    Alles anzeigen


    Und zwar schlaegt das Kompilieren in der Zeile L v = createObject(list.getClass()); fehl. Javac Output dazu:

    Code
    [javac] incompatible types
    [javac] found   : java.util.AbstractCollection
    [javac] required: L
    [javac]         L v = createObject(list.getClass());
    [javac]                           ^


    Kann mir einer erklaeren wieso, bzw. obs hier ne Loesung auch fuer den javac gibt?

    thx kubu


  • java-girl
    14
    java-girl
    Mitglied
    Reaktionen
    7
    Punkte
    2.037
    Beiträge
    357
    • 29. November 2006 um 13:55
    • #5

    Du gibst bei der Methode createObject(); ein T zurück.
    Ein T und L sind beide von AbstractCollection abgeleitet, allerdings ist ein L kein T und umgekehrt.
    Deswegen kommt auch die Fehlermeldung incompatible Types. Du kannst einem L kein T zuweisen, weil die beiden nichts voneinander wissen.
    Warum das allerdings mit Eclipse kompiliert, kann ich beim besten Willen nicht verstehen.
    Hoffe das hat dir geholfen.
    Mfg.
    java-girl

    There's no better place than 127.0.0.1!

  • kubuntu
    6
    kubuntu
    Mitglied
    Reaktionen
    2
    Punkte
    352
    Beiträge
    65
    • 29. November 2006 um 14:10
    • #6

    list.getClass() returned mir ja ein Objekt mit dem statischen Typ Class<? extends L>. Wenn ich damit die generische Methode createObject() aufrufe wird deren statischer Typ T gleich dem ? extends L und returned mir deshalb ein passendes Objekt vom statischen Typ ? extends L. Ich seh daran nicht, warum es nicht funktioneren sollte (und es funktioniert ja auch, unter Eclipse laeuft es einwandfrei).

    Bzw. hat das ueberhaupt mit dem Return-Typ zu tun? Der Fehler liegt ja anscheinend nicht am Return-Typ, sondern an dem Type des Parameters.


  • java-girl
    14
    java-girl
    Mitglied
    Reaktionen
    7
    Punkte
    2.037
    Beiträge
    357
    • 29. November 2006 um 14:23
    • #7

    Also für mich ist das klar.
    Es geht nicht darum was du gerade beschrieben hast, es geht, wie gesagt darum, dass zwar der dynamische Typ in diesem Fall ein L ist, aber dass kann man zu diesem Zeitpunkt nicht wissen!
    Wenn du schreiben würdest

    Code
    AbstractCollection v = createObject(list.getClass());


    Dann würde es gehen...

    Verständlich?
    Die ganze Sache ist etwas verwirrend finde ich *g*

    There's no better place than 127.0.0.1!

  • kubuntu
    6
    kubuntu
    Mitglied
    Reaktionen
    2
    Punkte
    352
    Beiträge
    65
    • 29. November 2006 um 14:31
    • #8

    Ne check ich immer noch nicht, sry wenn ich laestig bin :)
    L ist doch kein dynamischer Typ, sondern ein statischer. Wenn ich hab:

    Code
    AbstractList<Integer> v = new Vector<Integer>();
    filter(func, v);


    Dann hat L doch den Typ AbstractList<Integer>. Wenn ich den an createObject weitergebe wird Class<T> cl von createObject() zu Class<AbstractList<Integer>> und T dadurch AbstractList<Integer>.


  • java-girl
    14
    java-girl
    Mitglied
    Reaktionen
    7
    Punkte
    2.037
    Beiträge
    357
    • 29. November 2006 um 19:57
    • #9

    So, jetzt muss ich mich einmal entschuldigen.
    Ich war vollkommen auf dem falschen Dampfer und ehrlich gesagt weiß ich nicht was es da haben kann. Sorry für die Verwirrung die ich gestiftet hab!!!
    Eigentlich müsste es wirklich gehen....

    There's no better place than 127.0.0.1!

  • Maximilian Rupp 27. Dezember 2024 um 12:05

    Hat das Thema aus dem Forum Programmieren nach Entwicklung verschoben.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!

Benutzerkonto erstellen Anmelden

Rechtliches

Impressum

Datenschutzerklärung

  • Alles
  • Dieses Thema
  • Dieses Forum
  • Seiten
  • Forum
  • Lexikon
  • Erweiterte Suche
  • Deutsch
  • English
Zitat speichern