2013-08-15 8 views
6

Questo problema deriva dalla tipizzazione del costruttore di javax.validation.ConstraintViolationException. Accetta Set<ConstraintViolation<?>> come argomento.Impossibile digitare quando un argomento accetta Raccolta <X<?>>

Mentre è molto facile da ottenere un insieme di ConstraintViolation < X> dove X è un tipo concreto, sembra impossibile ottenere una serie di "ConstraintViolation <?>" Da qualsiasi API ben tipato. E non è possibile convertire il primo in quest'ultimo senza utilizzare alcuni calchi contorti. (Trasmissione a Set<? extends ConstraintViolation<?>> e quindi a Set<ConstraintViolation<?>>.)

Quindi voi ragazzi pensate che l'API sia sbagliata o io abbia torto (e perché)?

+3

Perché pensi che sia impossibile ottenere un 'Set >'? Puoi mostrare qualche esempio concreto, in cui ti vedi bloccato in questo numero? –

+0

Sembra che il costruttore debba prendere 'Set > invece. –

+2

Penso che sia un duplicato di http://stackoverflow.com/questions/12096846/how-do-i-construct-a-constraintviolationexception – Katona

risposta

4

L'API è errata. A meno che le implementazioni non debbano aggiungere nuovi ConstraintViolation<?> al set, dovrebbe accettare tutto il Set<? extends ConstraintViolation<?>>.

Ecco un esempio che illustra il motivo per cui questo è più flessibile (fornito da Paul Bellora, grazie):

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

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

+0

@OliCharlesworth Penso che potresti aver frainteso la risposta. –

+0

Immagino di poter passare qualsiasi tipo parametrizzato a 'ConstraintViolation '. –

2

L'API è sbagliato.

Idealmente ovunque vogliamo accettare un tipo generico covariante, dovremmo usare ? extends.

Alcune dichiarazioni generiche sono intrinsecamente covarianti, il che significa che devono sempre essere utilizzate con caratteri jolly, ad es. Iterator. Se uno Iterator viene utilizzato senza caratteri jolly, è quasi certamente sbagliato.

Il problema è che la sintassi dei caratteri jolly è così dettagliata che le persone vengono disattivate e spesso dimenticano di usarlo. Questo è molto diffuso anche nelle librerie core, ad es. restituisce Iterator<T>, mentre dovrebbe restituire Iterator<? extends T>.

La cancellazione, ironia della sorte, può risolvere questo problema. Sappiamo che uno Iterator<Apple> può essere utilizzato in modo sicuro come Iterator<Fruit> staticamente, e sappiamo che siamo in grado di trasmettere in modo deciso Iterator<Apple> a Iterator<Fruit> in modo dinamico, grazie alla cancellazione. Quindi vai avanti e fai il cast brutale.

+0

+1 Ma si noti che generalmente non è di aiuto restituire * tipi generici con '? estende però - i parametri del metodo sono dove possono aggiungere flessibilità. –

+0

È utile sottoclasse le implementazioni per restituire un 'Iterator ' come 'Iterator '. – ZhongYu

+0

Perché? Non rimuove semplicemente le informazioni? –

Problemi correlati