2016-05-17 4 views
0

Ich stieß auf ein Problem, für das ich keine Lösung finden konnte.Generics Wildcard ist nicht in der Lage, nach Genericetype zu konvertieren

Ich verwende oft eine Zuordnung, wo der Schlüssel und der Wert Objekte mit übereinstimmenden generischen Typen sind. Für jedes Paar sollten die Generika übereinstimmen. Obwohl die generischen Typen zwischen den Einträgen variieren können. (Ich nehme ein Beispiel zur Klarheit). Dies kann leicht mit der Verwendung der WildCard erreicht werden. Aus diesem Grund können Sie den Schlüssel oder Wert nicht in Kombination miteinander verwenden.

Betrachten Sie das Beispiel an der Unterseite. Es gibt keine (einfache) Möglichkeit, die Map so zu modifizieren, dass Cast-Exceptions ausgeführt werden. Obwohl ich immer noch nicht in der Lage sein werde, die Karte so zu benutzen, wie ich es innerhalb useEntries() versucht habe. Meine Frage ist also, gibt es einen Workaround dafür? Danke im Voraus!

public class GenericWildcardTest 
{ 
    static Map<GenericObject<?>, Function<?, ?>> map = new HashMap<>(); 

    public static <S> void put(GenericObject<S> genericObject, Function<S, S> function) 
    { 
     map.put(genericObject, function); 
    } 

    public static void useEntries() 
    { 
     for(Entry<GenericObject<?>, Function<?, ?>> currentEntry : map.entrySet()) 
      //The #apply(); part simply wont compile because of cast errors. 
      currentEntry.getKey().set(currentEntry.getValue().apply(currentEntry.getKey().get())); 
    } 



    // Simple Object with generic. 
    static class GenericObject<T> 
    { 
     private T object; 

     public GenericObject(T object) 
     { 
      this.object = object; 
     } 

     public void set(T object) 
     { 
      this.object = object; 
     } 

     public T get() 
     { 
      return this.object; 
     } 
    } 
} 
+0

Casting ist eine offensichtliche Problemumgehung. – shmosel

+0

Ich bin verwirrt von Ihrem Beitrag und was Sie fragen. Sie verwenden Generics und Wild Cards. Ich empfehle, dieses Tutorial vollständig durchzugehen, es deckt Generics und Wildcards ab und wird Ihre Probleme beleuchten. [Die Java ™ Tutorials: Generics (Aktualisiert)] (http://docs.oracle.com/javase/tutorial/java/generics/index.html) – Underbalanced

+0

@shmosel hast du wahrscheinlich gar nicht versucht, dies zu tun? da es nicht funktioniert. Ich habe sogar versucht, eine private Methode mit einer eigenen generischen Implementierung zu erstellen. aber es ist ziemlich einfach. ein generictype kann zu einem Platzhalter, aber nicht vicaversa – n247s

Antwort

2

Hier ist, wie Sie es mit dem Gießen zu tun:

@SuppressWarnings("unchecked") 
public static <S> void useEntries() { 
    for(Entry<GenericObject<?>, Function<?, ?>> currentEntry : map.entrySet()) { 
     GenericObject<S> key = (GenericObject<S>)currentEntry.getKey(); 
     Function<S, S> value = (Function<S, S>)currentEntry.getValue(); 
     key.set(value.apply(key.get())); 
    } 
} 

Diese Antwort geht davon aus, dass Ihre Karte in der Tat Function<S, S> enthält, nicht Function<GenericObject<S>, S>.

+0

Ich bevorzuge es, die Unterdrückung auf jeden der Umwandlungen einzeln zu setzen (zB '@SuppressWarnings (...) GenericObject key = ...') anstatt auf die gesamte Methode, so dass Sie nicht unbeabsichtigt weitere ungeprüfte Umwandlungen hinzufügen wenn Sie später die Methode ändern. Aber im Allgemeinen ist dies ein viel besserer Ansatz als rohe Typen. –

+1

@AndyTurner, einverstanden. Ich würde eigentlich einen Schritt weiter gehen und eine private Methode erstellen, um zu vermeiden, dass "T" offengelegt wird (und so stellt es tatsächlich einen einzelnen Typ dar), aber ich entschied mich, den einfachen Weg hier zu gehen. – shmosel

0

Sie können die useEntries Methode wie folgt umschreiben: ermöglicht

@SuppressWarnings("unchecked") 
public static void useEntries() { 
    for (Map.Entry<GenericObject<?>, Function<?, ?>> currentEntry : map.entrySet()) { 
     GenericObject key = currentEntry.getKey(); 
     Function value = currentEntry.getValue(); 
     key.set(value.apply(key.get())); 
    } 
} 

die Generika aus dem GenericObject und Function innerhalb der Methode Entfernen Sie die Anrufe auf reinen Object Instanzen zu machen. Es liegt dann in Ihrer Verantwortung, eine korrekte Eingabe zu gewährleisten. Die Annotation SuppressWarning entfernt Kompilierungswarnungen, die sonst gedruckt würden.

+0

dachte nicht daran. dumm einfach. Danke – n247s

+2

Verwenden Sie keine Rohtypen: Verwenden Sie Güsse. –

+1

Ich würde das Gießen vor rohen Typen empfehlen. Es gibt tatsächlich einen Fehler in diesem Code, der wegen der unformatierten Typen übersehen wird. – shmosel