2013-08-15 5 views
6

Dieses Problem rührt von der Eingabe des Konstruktors javax.validation.ConstraintViolationException her. Es akzeptiert Set<ConstraintViolation<?>> als Argument.Unmögliches Eingeben, wenn ein Argument eine Collection akzeptiert <X<?>>

Während es sehr einfach ist, eine Reihe von ConstraintViolation < X> wo X ist ein konkreter Typ zu erhalten, scheint es unmöglich, eine Reihe von "ConstraintViolation <?>" Von jedem gut typisierten API zu erhalten. Und es ist nicht möglich, das erstere zu dem letzteren zu konvertieren, ohne einige gewundene Abgüsse zu verwenden. (Casting zu Set<? extends ConstraintViolation<?>> und dann zu Set<ConstraintViolation<?>>.)

Also denkst du, dass die API falsch ist oder ich falsch liege (und warum)?

+3

Warum denken Sie, dass es unmöglich ist, einen 'Set >' zu bekommen? Können Sie ein konkretes Beispiel zeigen, wo Sie sich in dieser Ausgabe festgefahren fühlen? –

+0

Es sieht so aus, als müsste der Konstruktor 'Set <übernehmen? erweitert ConstraintViolation > 'stattdessen. –

+2

Ich denke, es ist ein Duplikat von http://stackoverflow.com/questions/12096846/how-do-i-construct-a-constraintviolationexception – Katona

Antwort

4

Die API ist falsch. Wenn die Implementierungen keine neuen ConstraintViolation<?> s zum Set hinzufügen müssen, sollten alle Set<? extends ConstraintViolation<?>> akzeptiert werden.

Hier ist ein Beispiel, das zeigt, warum diese flexibler ist (zur Verfügung gestellt von Paul Bellora, danke):

public class Main { 

    interface Foo<T> { } 

    interface SubFoo<T> extends Foo<T> { } 

    static class Bar { } 

    public static void main(String[] args) { 

     Set<Foo<?>> arg1 = null; 
     Set<SubFoo<?>> arg2 = null; 
     Set<Foo<Bar>> arg3 = null; 
     Set<SubFoo<Bar>> arg4 = null; 

     Set<Foo<?>> inflexibleParam; 
     inflexibleParam = arg1; //success 
     inflexibleParam = arg2; //incompatible types 
     inflexibleParam = arg3; //incompatible types 
     inflexibleParam = arg4; //incompatible types 

     Set<? extends Foo<?>> flexibleParam; 
     flexibleParam = arg1; //success 
     flexibleParam = arg2; //success 
     flexibleParam = arg3; //success 
     flexibleParam = arg4; //success 
    } 
} 

(ideone)

+1

Huh? http://ideone.com/5xeuqp –

+0

@OliCharlesworth Ich denke, dass Sie die Antwort möglicherweise missverstanden haben. –

+0

Ich denke, Sie können jeden parametrisierten Typ an 'ConstraintViolation ' übergeben. –

2

Die API ist falsch.

Im Idealfall, wo immer wir einen kovarianten generischen Typ akzeptieren möchten, sollten wir verwenden.

Einige generische Deklarationen sind inhärent kovariant, was bedeutet, dass sie immer mit Platzhalter, z. Iterator. Wenn ein Iterator ohne Wildcard verwendet wird, ist es fast sicher falsch.

Das Problem ist, die Wildcard-Syntax ist so ausführlich, Leute sind ausgeschaltet und oft vergessen, es zu verwenden. Dies ist sogar in Kernbibliotheken, z.B. Iterable<T>.iterator() gibt Iterator<T> zurück, während es Iterator<? extends T> zurückgeben sollte.

Erasure, ironisch, kann dieses Problem zu retten. Wir wissen, ein Iterator<Apple> kann sicher als Iterator<Fruit> statisch verwendet werden, und wir wissen, dass wir Iterator<Apple> to Iterator<Fruit> dynamisch rotieren können, dank Löschung. Also mach einfach die brutale Besetzung.

+0

+1 Aber beachten Sie, dass es im Allgemeinen nicht hilfreich ist, * generische Typen mit '? erweitert - obwohl - Methode Parameter sind, wo sie Flexibilität hinzufügen können. –

+0

Es ist hilfreich, Implementierungen abzuleiten, um einen 'Iterator ' als 'Iterator '. – ZhongYu

+0

Warum? Entfernt das nicht einfach Informationen? –

Verwandte Themen