2015-11-02 12 views
11

Ich habe einen parametrisierte Wert, dh zur Laufzeit aufgelöst:Wie vermeiden Sie eine ungeprüfte Umwandlung, wenn die generische Variable zur Laufzeit aufgelöst wird?

public class GenericsMain { 
    public static void main(String... args) { 
     final String tag = "INT"; 

     Field field = resolve(tag); 

     if (tag.equals("INT")) { 
      /* 
       In here I am using the "secret knowledge" that if tag equals INT, then 
       field could be casted to Field<Integer>. But at the same time I see an unchecked cast 
       warning at here. 

       Is there a way to refactor the code to be warning-free? 
      */ 
      Field<Integer> integerField = (Field<Integer>) field; 

      foo(integerField); 
     } 
    } 

    public static Field resolve(String tag) { 
     switch (tag) { 
      case "INT": 
       return new Field<>(1); 
      case "DOUBLE": 
       return new Field<>(1.0d); 
      default: 
       return null; 
     } 
    } 

    public static <T> void foo(Field<T> param) { 
     System.out.println(param.value); 
    } 

    static class Field<T> { 
     public final T value; 

     public Field(T value) { 
      this.value = value; 
     } 
    } 
} 

Gibt es eine Möglichkeit ungeprüft Guss in dem obigen Code zu vermeiden (mit einem langen Kommentar markiert)?

+2

Nicht direkt. (Java unterstützt keine Flow-Typen.) Sie könnten hier jedoch ein Besuchermuster verwenden. – aioobe

+1

Werfen Sie einen Blick auf diese Frage: http://stackoverflow.com/questions/1129795/what-is-suppresswarnings-unched-in-java – stevecross

+0

@aioobe Ich wäre wirklich nett, wenn Sie das mit einem Beispiel erarbeiten. –

Antwort

2

Sie können die Annotation dazu verwenden. Verwenden Sie die folgende Anmerkung:

@SuppressWarnings("unchecked") 
+4

Das wird funktionieren, aber meine Frage ist mehr über Code-Design und wie man die Warnung architektonisch vermeidet. –

+1

Sie können es nicht direkt in Java tun. –

6

Allgemeinen keine Möglichkeit, da Typ-Parameter auf Erklärung gebunden ist. Und was Sie tun möchten, ist statische Deklaration basierend auf dem Laufzeitwert zu ändern.

Sie können jedoch Bereich von ungeprüften Guss minimieren durch parametrisierte Methode deklarieren, die Parameter eingeben

@SuppressWarnings("unchecked") 
private static <T> Field<T> asParameterized(Field<?> field) { 
    return (Field<T>) field; 
} 

und verwenden Sie dann fügt

Field<Integer> intField = GenericsMain.<Integer> asParameterized(field); 
+1

Bitte lesen Sie über Haufen Verschmutzung https://docs.oracle.com/javase/tutorial/java/generics/nonReifableVarargsType.html#heap_pollution. –

+0

Einverstanden, deshalb gibt der Compiler die Warnung aus, aber dieser Fall sieht sicher aus - es gibt genaues "geheimes" Wissen darüber, welcher Typ Parameter sein sollte. –

+0

Nun, wenn Sie auf Ihre "geheime" Wissen Robustheit vertrauen, dann denke ich, dass es in Ordnung ist. Aber du könntest einen schlechten Tag haben und perfekt 'Feld intField = asParameterized (field)' mit 'field' halten ein Doppel ... Nicht sehr einfach zu beheben und zu debuggen ... –

3

Vielleicht. Anstelle von dummen String-Tags können Sie einen Typ verwenden, der die Typinformationen codiert. Sehen Sie dieses Blog-Post: http://blog.pdark.de/2010/05/28/type-safe-object-map/

public class FieldKey<T> { 
    private String name; 

    public FieldKey(String name) { 
     this.name = name; 
    } 

    public String name() { 
     return name; 
    } 
} 

sowie den Konstruktor von Field-public Field(FieldKey<T> key, T value) ändern.

Sie müssen noch casten, aber Kompilierungszeitprüfungen werden sicherstellen, dass sie niemals fehlschlagen.

+3

Und wie werden Sie richtig parametrisiert werden Deklarationen von FieldKey-Instanzen? :) Ich bin mir ziemlich sicher, dass irgendwas irgendwo deaktiviert werden sollte, um die Schleife zu durchbrechen –

+0

Bitte schauen Sie sich den Code in meinem Blogpost an; Sie können die Umwandlungen in der 'get (TypedMapKey)' Methode sehen. Sie können die Besetzung auch in die Schlüsselklasse verschieben: public T get (Feld f) '. Wie gesagt, der Hauptvorteil meines Ansatzes besteht darin, dass Sie den Typ sowohl für die Zuweisung als auch für das Lesen verwenden können und daher sicherstellen, dass der Cast nicht fehlschlagen kann. –

1

Alle Antworten sind in Ordnung, aber ich denke, es gibt nicht genug Betonung auf warum Sie bekommen eine Warnung und sind Casting.

Sie sind explizit umgehen das Typsystem durch Ausführen einer ungeprüften Besetzung. Wenn Sie sagen: "Ich habe Informationen über diesen Typ, der dem Compiler nicht zur Verfügung steht" - sagen Sie dem Compiler, den Sie besser kennen.

Das ist natürlich ein möglicher und vernünftiger Anwendungsfall: andernfalls wären diese Umwandlungen nicht erlaubt, aber eine Warnung ist gut, da sie anzeigt, dass Sie wirklich sind, was der Typ ist.

Das macht perfekt Sinn. In der Tat, wenn Sie Bibliotheken wie GSON, die Serialisierung überprüfen, sind sie full of these warnings and supressions.

Mach dir keine Sorgen über deinen Code - alles ist in Ordnung. Wenn es eine Möglichkeit gäbe, den Compiler "auszutricksen", um die Warnung nicht auszugeben, die auf der anderen Seite ein ernstes Problem gewesen wäre :)