2012-11-03 13 views
5

Ci scusiamo per il titolo vago. Ho questo pezzo di codice che compila su Eclipse Juno (4.2), ma non javac (1.7.0_09):Java CRTP e caratteri jolly: il codice viene compilato in Eclipse ma non `javac`

package test; 

public final class Test { 
    public static class N<T extends N<T>> {} 

    public static class R<T extends N<T>> { 
     public T o; 
    } 

    public <T extends N<T>> void p(final T n) {} 

    public void v(final R<?> r) { 
     p(r.o);  // <-- javac fails on this line 
    } 
} 

L'errore è:

 
Test.java:13: error: method p in class Test cannot be applied to given types; 
     p(r.o); 
     ^
    required: T 
    found: N<CAP#1> 
    reason: inferred type does not conform to declared bound(s) 
    inferred: N<CAP#1> 
    bound(s): N<N<CAP#1>> 
    where T is a type-variable: 
    T extends N<T> declared in method <T>p(T) 
    where CAP#1 is a fresh type-variable: 
    CAP#1 extends N<CAP#1> from capture of ? 
1 error 

Quindi le domande sono:

  1. Si tratta di un errore javac o di Eclipse?

  2. C'è un modo per fare questo compilare su javac, senza cambiare la firma del metodo v (ad esempio, mantenere il carattere jolly)?

    So che cambiarlo in <T extends N<T>> void v(final R<T> r) lo fa compilare, ma mi piacerebbe sapere se c'è modo di evitare questo per primo. Inoltre, il metodo p non può essere modificato in <T extends N<?>> void p(final T n) perché il contenuto ha tipi che richiedono il vincolo esatto T extends N<T>.

+0

@Nambari: è anche 1.7. Inoltre, Eclipse non usa 'javac' per compilare il codice, ma il suo stesso compilatore. – kennytm

+0

Compila nella mia eclissi con java 6 quale versione di java stai usando? –

+0

@AmitD: Sì, funziona su Eclipse sia su 1.6 che su 1.7, ma non verrà compilato con OpenJDK 6 e 7's javac, né [Sun's JDK 6 su ideone] (http://ideone.com/Z03W7V). – kennytm

risposta

6

caratteri jolly sono limitati nel senso che rompono le espressioni ricorsive come T extends X<T> che parametri di tipo consentono. Sappiamo quello che stai cercando di fare è sicuro in base alla seguente:

  1. r.o è di tipo T (dichiarata da R), che è o si estende N<T>.
  2. Il metodo p accetta un argomento di tipo T (dichiarato da p), che è anche o estende N<T>.
  3. Quindi, anche se r viene immesso come R<?>, una chiamata p(r.o) dovrebbe essere teoricamente legale.

Questo è probabilmente il ragionamento del compilatore di eclipse (noto per rendere le tolleranze corrette per alcune sfumature di generici dove javac doesn't).

Supponendo che si desidera compilare con javac e non può cambiare la firma di v come lei ha ricordato, il meglio che puoi fare è ricorrere all'utilizzo di un tipo grezzo, che "opta fuori" di controllo tipo generico:

public void v(final R<?> r) { 
    //necessary to placate javac - this is okay because [insert above reasoning] 
    @SuppressWarnings("rawtypes") 
    N nRaw = r.o; 
    p(nRaw); 
} 
Problemi correlati