2016-04-15 17 views

Antwort

4

Ich glaube, das ist der Grund für die Warnung: Java erlaubt Downcasting, das heißt, ein Objekt vom Typ X in eine Unterklasse von X umwandeln. Dies erfordert jedoch eine Überprüfung zur Laufzeit. Zum Beispiel:

Object x1 = <... something that returns an object that may be a String ...>; 
String x2 = (String)x1; 

Die Besetzung wird versuchen x1 als String zu behandeln. Aber x1 kann jede Object sein. Es kann ein String sein oder auch nicht. Der Cast funktioniert nur, wenn x1 tatsächlich ein String ist; Ansonsten erhalten Sie zur Laufzeit einen ClassCastException.

Das Problem in Ihrem Code ist, dass T ist eine Unterklasse von View, was bedeutet, dass die Besetzung würde normalerweise die gleiche Art von Prüfung zur Laufzeit durchgeführt werden. Wegen des Löschens des Typs hat das Programm jedoch zu diesem Zeitpunkt des Codes keine Informationen über die Klasse T, was bedeutet, dass es die Überprüfung nicht durchführen kann. So erhalten Sie eine Warnung über das Programm mit einem ungeprüften Vorgang. Das Programm kann nicht garantieren, dass bei Rückgabe dieser Methode das zurückgegebene Objekt tatsächlich eine Instanz der Klasse T ist.

Ich habe einige Testfälle ausprobiert und festgestellt, dass die Überprüfung oft auf die Aussage Aufrufe die generische Methode stattfindet. Angenommen, View2 erweitert View, und Sie möchten find in einer Weise verwenden, die eine View2 zurückgibt. Dann:

View2 v = YourClass.<View2>find(x, id); 

Wenn das Objekt von findViewById gefunden ist nicht wirklich ein View2, erhalten Sie eine ClassCastException bekommen. Aber:

View v = YourClass.<View2>find(x, id); 

Angenommen findViewById gibt eine andere Ansicht. Basierend auf meinen Tests wird dies keine Ausnahme auslösen, obwohl der Typparameter View2 ist; Da dies in eine View zugewiesen wird, die gut funktioniert, wenn das Ergebnis eine andere Ansicht ist, keine Überprüfung für View2 jemals auftritt.

String s = YourClass.<View2>find(x, id).toString(); 

Angenommen, findViewById gibt eine andere Ansicht zurück. Wenn ich das versuchte, dachte ich, dass es keine Ausnahme werfen würde, weil die andere Ansicht auch toString() (wie alle Object s) hätte. Aber das hat ClassCastException geworfen.

Ich weiß nicht, ob es eine gute Möglichkeit gibt, es zu beheben. Eine Möglichkeit ist, einen dritten Parameter find hinzufügen, um die Klasse von T zu bezeichnen, und verwenden Sie seine cast Methode:

public static <T extends View> T find(View view, int id, Class<T> theClass) { 
    return theClass.cast(view.findViewById(id)); 
} 

View v = YourClass.find(x, id, View2.class); 

Dies funktioniert - es löst eine Ausnahme von der cast() Methode, wenn findViewById die falsche Klasse zurückgibt. Das Hinzufügen eines dritten Parameters zu jeder Verwendung ist jedoch möglicherweise nicht ansprechend, obwohl Sie dadurch möglicherweise einen expliziten generischen Typparameter aus dem Aufruf entfernen können.

Ich denke, dies ist ein Fall, wo es ist OK, um die Warnung zu ignorieren, und verwenden Sie @SuppressWarnings("unchecked") die Warnung angezeigt werden, zu stoppen, wenn Sie mit der Möglichkeit OK sind, dass manchmal kann das Programm fortsetzen, anstatt eine Ausnahme zu werfen, wenn findViewById gibt die falsche Art der Ansicht zurück.

() Haftungsausschluss: Meine Tests wurden mit Java 8 durchgeführt. Ich habe nichts verwendet, was in Java 7 nicht gültig wäre. Aber wenn Android Java 7 noch nicht vollständig implementiert hat, habe ich einiges von dem, was ich geschrieben habe könnte falsch sein.)

Verwandte Themen