2012-03-24 17 views
115

Eventuali duplicati:
Why should the interface for a Java class be prefered?Polymorphism: Perché utilizzare "List list = new ArrayList" anziché "ArrayList list = new ArrayList"?

Quando devo usare

List<Object> list = new ArrayList<Object>(); 

ArrayList eredita da List, quindi se alcune caratteristiche in ArrayList non sono in List, poi ho avrà perso alcune delle funzionalità di ArrayList, giusto? E il compilatore noterà un errore nel tentativo di accedere a questi metodi?

+0

Oh. Mi dispiace. perché cambio in 'oggetto', quindi lo dimentico. – hqt

+6

@duffymo - La domanda è la seguente: "La nuova lista ()' non funziona. È una domanda completamente diversa. –

+2

Non è una domanda duplicata. Il possibile duplicato ha una domanda generica ma un dettaglio specifico. Trovo che questa domanda nel titolo sia più pertinente/in sincronia con ciò che è effettivamente richiesto. – Dexters

risposta

205

Il motivo principale per farlo è disaccoppiare il codice da un'implementazione specifica dell'interfaccia. Quando si scrive il codice come questo:

List list = new ArrayList(); 

il resto del codice sa solo che i dati è di tipo List, che è preferibile perché consente di passare tra le diverse implementazioni dell'interfaccia List con facilità.

Ad esempio, supponiamo che stiate scrivendo una libreria di terze parti abbastanza grande e affermate che avete deciso di implementare il nucleo della libreria con uno LinkedList.Se la tua libreria si basa pesantemente sull'accesso agli elementi di questi elenchi, alla fine scoprirai di aver preso una decisione di progettazione scadente; ti renderai conto che avresti dovuto usare un ArrayList (che dà O (1) tempo di accesso) invece di un LinkedList (che dà O (n) tempo di accesso). Supponendo che tu abbia programmato un'interfaccia, fare un tale cambiamento è facile. Si potrebbe semplicemente cambiare l'istanza di List da,

List list = new LinkedList(); 

a

List list = new ArrayList(); 

e voi sapete che questo funzionerà perché avete scritto il codice per seguire il contratto fornito dall'interfaccia List.

D'altra parte, se si fosse implementato il nucleo della libreria utilizzando LinkedList list = new LinkedList(), effettuare tale modifica non sarebbe così facile, in quanto non vi è alcuna garanzia che il resto del codice non faccia uso di metodi specifico per la classe LinkedList.

Tutto sommato, la scelta è semplicemente una questione di design ... ma questo tipo di design è molto importante (specialmente quando si lavora su progetti di grandi dimensioni), in quanto vi permetterà di apportare modifiche specifiche per l'implementazione in seguito senza rompere codice esistente.

+4

spiegazione chiara. :) – coder247

+44

Molte persone non riescono a dire che è perfettamente accettabile istanziarlo come variabile locale tramite ArrayList list = new ArrayList(). È davvero utile utilizzare l'interfaccia Elenco nella firma del metodo o come il tipo di una variabile di livello di classe. A chi importa se devi tornare più tardi e modificare la dichiarazione del metodo locale? L'intero vantaggio arriva quando esponi un elenco ad altri metodi o librerie, ecc. – GreenieMeanie

+5

È vero, grazie per averlo indicato. In effetti, ora che ci penso, probabilmente avrebbe avuto più senso per me dare un esempio dal punto di vista di un cliente, piuttosto che dal programmatore stesso. In entrambi i casi, l'uso di 'List list = new ArrayList()' è una questione di garantire che non si interrompa il codice esistente. –

63

Si chiama programmazione all'interfaccia. Questo sarà utile nel caso in cui si desideri passare a qualche altra implementazione di List in futuro. Se desideri alcuni metodi in ArrayList, dovrai programmare l'implementazione che è ArrayList a = new ArrayList().

6

Ciò consente di scrivere qualcosa di simile a:

void doSomething() { 
    List<String>list = new ArrayList<String>(); 
    //do something 
} 

In seguito, si potrebbe desiderare di cambiare per:

void doSomething() { 
    List<String>list = new LinkedList<String>(); 
    //do something 
} 

senza dover cambiare il resto del metodo.

Tuttavia, se si desidera utilizzare un CopyOnWriteArrayList per esempio, si avrebbe bisogno di dichiararlo come tale, e non come un elenco se si voleva usare la sua metodi aggiuntivi (addIfAbsent per esempio):

void doSomething() { 
    CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>(); 
    //do something, for example: 
    list.addIfAbsent("abc"); 
} 
+1

Come per il commento @GreenieMeanie della risposta accettata, questa modifica non ha importanza in quanto si tratta di una variabile locale. – Ram

5

Io uso quella costruzione ogni volta che non voglio aggiungere complessità al problema. È solo una lista, non c'è bisogno di dire che tipo di List è, poiché non ha importanza per il problema. Uso spesso la raccolta per la maggior parte delle mie soluzioni, poiché, alla fine, il più delle volte, per il resto del software, ciò che conta davvero è il contenuto che contiene e non voglio aggiungere nuovi oggetti alla raccolta .

Inoltre, si utilizza questa costruzione quando si pensa che si desideri modificare l'implementazione della lista che si sta utilizzando. Diciamo che stavi usando la costruzione con un ArrayList, e il tuo problema non era thread-safe. Ora, vuoi renderlo thread-safe, e per una parte della tua soluzione, ad esempio, cambierai per usare un Vector. Per quanto riguarda gli altri usi di quella lista non importa se si tratta di una AraryList o di un Vector, solo una lista, non saranno necessarie nuove modifiche.

2

In generale, si desidera programmare su un'interfaccia. Ciò consente di scambiare l'implementazione in qualsiasi momento. Questo è molto utile specialmente quando si passa un'implementazione che non si conosce.

Tuttavia, ci sono alcune situazioni in cui si preferisce utilizzare l'implementazione concreta. Ad esempio quando serializzare in GWT.

17

Questo è anche utile quando si espone un'interfaccia pubblica. Se si dispone di un metodo come questo,

public ArrayList getList(); 

Poi si decide di cambiarla a,

public LinkedList getList(); 

Chiunque stava facendo ArrayList list = yourClass.getList() sarà necessario modificare il loro codice. D'altra parte, se lo fai,

public List getList(); 

Cambiare l'implementazione non cambia nulla per gli utenti della tua API.

+0

yourClass.getList() credo sia il caso d'uso più pratico che ho trovato. Grazie mille :) –

4

Credo che il nucleo della tua domanda è il motivo per cui a program to an interface, not to an implementation

Semplicemente perché un'interfaccia ti dà più l'astrazione, e rende il codice più flessibile e resistente ai cambiamenti, perché è possibile utilizzare diversi implementazioni dello stesso interfaccia (in questo caso potresti voler cambiare la tua implementazione di List in una linkedList invece di una ArrayList) senza cambiarne il client.

10

Penso che la risposta di @ tsatiz sia in gran parte corretta (programmare un'interfaccia anziché un'implementazione). Tuttavia, programmando nell'interfaccia non si perderà alcuna funzionalità. Lasciatemi spiegare.

Se si dichiara la variabile come List<type> list = new ArrayList<type> in realtà non si perde qualsiasi funzionalità di ArrayList.Tutto ciò che devi fare è lanciare il tuo list su un ArrayList. Ecco un esempio:

List<String> list = new ArrayList<String>(); 
((ArrayList<String>) list).ensureCapacity(19); 

In definitiva penso tsatiz è corretto come una volta che si esegue il cast a un ArrayList non sei più la codifica a un'interfaccia. Tuttavia, è comunque buona norma eseguire inizialmente il codice su un'interfaccia e, se in seguito diventa necessario, codificare un'implementazione, se necessario.

Spero che questo aiuti!

+0

Questo è molto facile e chiaro. – CopsOnRoad