2012-03-13 17 views
9

ho questo due interfacce e classi:parametri generici ridondanti

public interface Identifiable<T> { 
    T getId(); 
} 

public interface GenericRepository<T extends Identifiable<K>, K> { 
    T get(K id); 
} 

public class MyEntity implements Identifiable<Long> { 

    private Long id; 

    public Long getId() { 
     return id; 
    } 
} 

public class MyService { 
    private GenericRepository<MyEntity, Long> myEntityRepository; 
} 

tutto funziona come desiderato. Ma a mio parere il secondo parametro generico in GenericRepository (K) è ridondante. Perché so che è un MyEntity identificabili, penso che sarebbe bello se posso finalmente usare in questo modo:

public class MyService { 
    private GenericRepository<MyEntity> myEntityRepository; 
} 

Ma sto cercando cose diverse senza riuscirvi. È possibile? Se no, perché no?

UPDATE: Rispondere ad alcune risposte. Penso che il compilatore sappia qualcosa su quale tipo è il generico in MyEntity. Ad esempio:

public class MyEntityGenericRepository implements GenericRepository<MyEntity, Long> { 
    // compiles... 
} 

public class MyEntityGenericRepository implements GenericRepository<MyEntity, String> { 
    // compiler says: "Bound mismatch: The type MyEntity is not a valid substitute for the bounded parameter <T extends Identifiable<K>> of the type GenericRepository<T,K>" 
} 

risposta

7

Non penso che tu possa ometterlo. Con T extends Identifiable<K> si vuole dire che il parametro di tipo generico deve essere un Identifiable. Dato che Identifiable è una classe generica, è necessario menzionare anche il suo parametro di tipo generico (se si vuole giocare secondo le regole che sono - se lo si omette, si perde tutta la sicurezza di tipo generico per GenericRepository, a causa delle regole di retrocompatibilità). Si noti inoltre che K viene effettivamente utilizzato come tipo di parametro di GenericRepository.get. E poiché quel tipo può essere diverso da T, è necessario soddisfare il compilatore dichiarandolo come un altro parametro di tipo generico di GenericRepository. Altrimenti il ​​compilatore non ha modo di sapere cosa sia K.

+0

Grazie, ma io non sono d'accordo . Per favore, vedi la mia modifica. – sinuhepop

+3

@sinuhepop, ovviamente il compilatore può verificare che il tipo effettivo di 'K' corrisponda a quello del parametro type in 'Identifiable '. Tuttavia, è necessario * dichiarare * K come un parametro di tipo generico (e di conseguenza passare il suo valore effettivo nel punto di istanziazione). Questo è esattamente come funziona la lingua. Hai ragione che questa conoscenza * potrebbe * in teoria essere dedotta dal compilatore, ma non è per ora, e per molti anni ancora ... se mai (sfortunatamente, lo sviluppo di Java si sta muovendo solo molto lentamente in quella direzione. ..). –

3

Non è ridondante dal punto di vista della classe GenericRepository. Quando ha metodi come T get(K id), non può sapere quali tipi dell'argomento id può accettare diversamente. È possibile scrivere il seguente:

interface GenericRepository<T extends Identifiable<?>> { 
    T get(Object id); 
} 

Ora non c'è bisogno di scrivere Long come un parametro di tipo, ma si perde la possibilità di verificare se il metodo get viene utilizzato correttamente al momento della compilazione. Quindi la variabile type ha uno scopo specifico.

E per quanto riguarda la dichiarazione di campo, quando si dispone di un tipo generico, è necessario specificare tutte le variabili di tipo che utilizza. Naturalmente, si potrebbe obiettare che sarebbe bello se la lingua potesse capire che uno dei valori dei parametri può essere dedotto dall'altro, ma è discutibile.

+0

Per favore guarda la mia edizione. Sembra che il compilatore possa inferire il tipo in qualche modo. – sinuhepop

+0

@sinuhepop, no, non sta inferendo alcun tipo lì, solo confrontando l'uguaglianza di due parametri di tipo definiti concreti. (Un semplice esempio di) tipo di inferenza è [questo] (http://docs.oracle.com/javase/tutorial/java/generics/gentypeinference.html) (implementato in Java 7). –

0

Se non sbaglio, i generici verranno tutti compilati come se fossero solo Object. Ora la sintassi è (difficile) verificata per garantire che non si stia mettendo mela con le arance perché i generici sono stati aggiunti dopo la progettazione iniziale di Java. questo è il motivo per cui i generici sono così costretti ...

-1

Perché non è possibile rimuovere secondo K da,

public interface GenericRepository<T extends Identifiable<K>, K> { 

Quindi, piuttosto che averlo come sopra, possiamo avere come

public interface GenericRepository<T extends Identifiable<K>> { 

By questo possiamo fare quello che vuoi fare.

+0

Sì, ma sfortunatamente il compilatore dice "K non può essere risolto con un tipo". – sinuhepop

0

Funzionerebbe con (vale a dire.compila)

public interface GenericRepository<T extends Identifiable> { 
    T get(T id); 
} 

ma si dice comunque che Identifiable è un tipo non elaborato e che dovrebbe essere parametrizzato.

Spero che aiuti.

+0

Questo non è esattamente lo stesso - hai dichiarato 'get' come un argomento di tipo' T' piuttosto che 'K'. Probabilmente questo è il punto cruciale della domanda, come avere un riferimento a 'K' all'interno della classe senza doverlo dichiarare durante la costruzione, quindi è un po 'sfacciatamente aggirarlo. :) –

+0

Direi che non è possibile avere un riferimento K all'interno della classe senza doverlo dichiarare durante la costruzione. L'unica altra cosa che potrei pensare sarebbe l'interfaccia pubblica GenericRepository > { T get (T id); } – aretai

+1

Sì, questa è la domanda: "** È possibile? In caso contrario, perché no? **" –

1

Non molto si può fare, altro che introdurre un'interfaccia che solo affina GenericRepository

public interface LongKeyedRepository<T extends Identifiable<Long>> 
     extends GenericRepository<T, Long> { { 
    //No new methods need to be defined 
    } 

Poi si può avere

private LongKeyedRepository<MyEntity> myEntityRepository; 

ecc

+0

Grazie. Attualmente sto facendo qualcosa di simile a questo (ho semplificato la mia struttura un po '). Ma non mi piace troppo, e non capisco perché sia ​​necessario. – sinuhepop

Problemi correlati