|
| HOMEPAGE | INDICE FORUM | REGOLAMENTO | ::. | NEI PREFERITI | .:: | RSS Forum | RSS News | NEWS web | NEWS software | |
| PUBBLICITA' | | | ARTICOLI | WIN XP | VISTA | WIN 7 | REGISTRI | SOFTWARE | MANUALI | RECENSIONI | LINUX | HUMOR | HARDWARE | DOWNLOAD | | | CERCA nel FORUM » | |
![]() |
#1 |
Gold Member
Top Poster
Registrato: 04-09-2002
Loc.: Roma
Messaggi: 4.022
![]() |
[JAVA] Funzione delle interfacce
Perché esistono le interfacce?? Qual'è la loro utilità?' Cioè, passi l'uso per la gestione degli eventi, ma ad esempio qual'è la logica che ha spinto i programmatori sun a rendere ad esempio "ResultSet" (presente nel package sql) una interfaccia anziché una classe?? Che logica c'è stata dietro? tnx! ![]() |
![]() |
![]() |
![]() |
#2 |
Gold Member
Top Poster
Registrato: 18-07-2002
Messaggi: 6.399
![]() |
Ciao
![]() Le interfacce permettono di dichiarare un insieme di signature di metodi (nome del metodo, tipo di parametro in uscita, parametri in ingresso con il loro tipo). Una interfaccia può essere implementata da una o più classi differenti, che - tramite la direttiva implements - si "impegnano" (pena la non compilazione) a fornire (almeno) i metodi dichiarati nell'interfaccia, rispettando le regole sui tipi (*). Uno si può chiedere, in effetti, a che caspita servano queste interfacce: non è forse più comodo scrivere direttamente la classe piuttosto che dichiarare la signature dei metodi in un file e la loro implementazione in un altro? A prima vista sì, sembrerebbe più comodo, ma a ben guardare - almeno in alcuni casi - assolutamente no. Il primo motivo è che una classe può estendere una sola altra classe (almeno in Java, non così in altri linguaggi dove esiste l'ereditarietà multipla), ma può implementare più interfacce. Si tratta quindi di una questione di "modularità", di divisione delle funzionalità: se, dato un insieme di metodi, tutto l'insieme dei metodi fosse contenuto in una classe A, ogni classe interessata a fornire/ridefinire/etc anche uno solo dei metodi di A, dovrebbe implementare anche tutti gli altri metodi. Se invece i vari metodi di A fossero divisi in più classi, si potrebbero scegliere in maniera più fine i metodi da implementare. Questa divisione però fa sì che una stessa classe non possa ridefinirli tutti (può estendere una sola classe), ma solo un sottoinsieme: da qui l'uso delle interfacce. Un secondo motivo è invece molto più importante: definire un'interfaccia è - con le dovute differenze - come definire un protocollo: si danno delle regole, e chi vuole aderire al protocollo deve rispettare quelle regole. Allo stesso modo, chi vuole implementare un'interfaccia, deve fornire tutti i metodi dichiarati dall'interfaccia. In questo modo si può definire una base comune, eventualmente adottata/implementata da più classi differenti. Per esempio si può definire un'interfaccia per gestire un conto bancario, con i metodi apri, chiudi, preleva, deposita, e i relativi parametri. Ora tutti potranno implementare una propria classe (A, B, C, anche in maniera differente una dall'altra, a seconda delle possibili esigenze diverse) che aderisce alle specifiche dell'interfaccia; una classe terza X, sapendo che A, B, C implementano l'interfaccia del conto bancario, può senza timore chiamare metodi di una di queste classi, basandosi su quelli presenti nell'interfaccia. (NB: il fatto che A e B implementino entrambe il metodo preleva() non dà alcuna garanzia sul fatto che i due metodi A.preleva e B.preleva si comportino allo stesso modo agli effetti esterni: magari uno effettua correttamente il prelievo, l'altro no. Implementare un'interfaccia è una questione sintattica, non semantica, anche se è ragionevole che venga rispettata anche la semantica del metodo) Pensando a uno stesso servizio fornito da più gestori la convenienza di questo approccio risulta evidente ![]() Non per questo però bisogna sempre utilizzare un'interfaccia: se non è necessario stabilire una base comune (eventualmente anche fra parti logicamente differenti di uno stesso progetto, non necessariamente fra progetti differenti) non occorre dichiarare un'interfaccia. (*) Le regole sui tipi dei parametri sono le stesse che valgono quando si fa l'ovverride di un metodo: i parametri in ingresso devono essere un sopratipo di quelli originali (per esempio un generico numero rispetto a un intero, si è in sostanza "più permissivi"), mentre il parametro di uscita deve essere un sottotipo di quello originale (per esempio un intero al posto di un numero generico, si è in sostanza "meno permissivi"), questo per garantire il corretto funzionamento di altre classi che utilizzano i metodi di cui si è fatto l'override o che si sono implementati rispetto a un'interfaccia. Ciao ![]() |
![]() |
![]() |
![]() |
#3 |
Gold Member
Top Poster
Registrato: 04-09-2002
Loc.: Roma
Messaggi: 4.022
![]() |
Caspita, super esauriente (Y)
Ottimo, grazie 1000! ![]() |
![]() |
![]() |
![]() |
#4 |
Gold Member
Top Poster
Registrato: 04-09-2002
Loc.: Roma
Messaggi: 4.022
![]() |
Ok, ma c'è ancora na cosetta che non mi è chiara:
come mai alcune interfacce le implemento nella classe con la parola chiave implements mentre ad esempio l'interfaccia ResultSet non viene implementata (quindi è dichiarata come una normalissima variabile) ma posso comunque usare tutti i metodi che contiene?? |
![]() |
![]() |
![]() |
#5 |
Gold Member
Top Poster
Registrato: 18-07-2002
Messaggi: 6.399
![]() |
Puoi fare un esempio? (con codice tuo e codice che usi, nel caso)
Credo di aver capito cosa intendi, ma non vorrei scrivere un papiro per nulla ![]() |
![]() |
![]() |
![]() |
#6 |
Gold Member
Top Poster
Registrato: 04-09-2002
Loc.: Roma
Messaggi: 4.022
![]() |
Mettiamo il caso che io voglia scrivere una mia interface.
Questa ad esempio: Codice:
public interface DownloadersInterface { public void metodoUno(); public void metodoDue(); } Codice:
public class ClasseProva implements DownloadersInterface { public static void main(String[] args) { } public void metodoUno() { System.out.println("Metodo 1"); } public void metodoDue(){} } Ok, adesso però l'interfaccia viene usata in modo totalmente diverso: Codice:
public class AltraClasse { public metodoDB() { . . . ResultSet rs = st.executeQuery("SELECT * FROM tabella"); int i = 0; String s[] = new String[10]; while(rs.next()) { s[i] = rs.getString("Nome"); i++; } } } il metodo executeQuery() torna un valore ResultSet ovvero una interfaccia e già qua qualcosa non mi torna. Cioè se fosse tornato un int, String...sarebbe andato bene, ma un valore ResultSet proprio non riesco ad immaginarmelo. Ma il succo della questione è: come diavolo si possono usare metodi di una interfaccia (in questo caso next() e getString()) dal momento che questa non è istanziabile e dal momento che non sono stati ridefiniti i metodi visto che non l'abbiamo implementata?? tnx! ![]() |
![]() |
![]() |
![]() |
#7 |
Gold Member
Top Poster
Registrato: 18-07-2002
Messaggi: 6.399
![]() |
Ok, è come pensavo
![]() La domanda è più che lecita, e anche spontanea: tutti martellano con la regola "non puoi istanziare un'interfaccia", "non puoi istanziare un'interfaccia", "chi istanzia un'interfaccia verrà dato in pasto al garbage collector" ![]() In effetti la spiegazione è semplice: la regola non è violata, nessuno istanzia un'interfaccia, ma semplicemente restituisce un oggetto A che è di tipo X, dove X è un'interfaccia. Ciò vuol dire che in generale l'oggetto A sarà di una classe B, anche non nota a priori, ma che per chi se lo ritrova fra le mani, questo avrà disponibili solo e soltanto i metodi dichiarati dall'interfaccia X. Non c'è quindi nessun oggetto che è stato creato con new ResultSet(), semplicemente a te questo oggetto viene mostrato come aderente a una determinata specifica formale. Questo per rispondere alla prima parte della domanda; la risposta alla seconda parte ora vien da sé. Quando il metodo executeQuery dell'oggetto st viene invocato, questo costruisce un oggetto - sa lui quale - che appartiene a una classe che implementa l'interfaccia resultSet, e poi te lo restituisce dichiarandotelo di tipo resultSet, e quindi garantendoti su questo oggetto tutti e soli i metodi dichiarati nell'interfaccia. Quando poi tu invochi metodi su quest'oggetto, verranno chiamate in causa le implementazioni che di questi metodi sono state fatte nella classe cui veramente fa capo l'oggetto rs. Una delle utilità delle interfacce sta proprio qui: chi ha scritto la classe di cui st è istanza ha potuto scegliere come tipo di risultato quello che a lui sembrava più congeniale ed efficiente (un array, una lista ordinata, uno heap, un albero, ...), senza preoccupazioni sul tipo di dato restituito e su possibili differenze da un tipo all'altro, e - cosa oltremodo importante - su eventuali modifiche nella scelta del tipo di risultato restituito: st potrà scegliere una volta un array, una volta un albero, ma tu riceverai sempre un resultSet, e non avrai problemi di cambiamento di gestione del tuo risultato a seconda della scelta di st. Ora devo scappare, ho qualche altra roba da mettere ma la butto giù quando torno da lezione ![]() |
![]() |
![]() |
![]() |
Utenti attualmente attivi che stanno leggendo questa discussione: 1 (0 utenti e 1 ospiti) | |
Strumenti discussione | |
|
|
![]() |
||||
Discussione | Autore discussione | Forum | Risposte | Ultimo messaggio |
Solo 3% (non 44%) le perdite delle Major dovute al P2P | Macao | Segnalazioni Web | 0 | 24-01-2008 05.04.51 |
[OOP] Tentativo di cercare delle linee guida... | Fast-M | Programmazione | 1 | 18-10-2007 21.19.34 |
La musica gode con il P2P | Macao | Segnalazioni Web | 0 | 04-10-2007 00.44.07 |
Problema con il comando Apri delle cartelle | Maximus | Windows 7/Vista/XP/ 2003 | 1 | 07-02-2005 11.26.26 |
Che ne pensate delle nuove tariffe Enel? | handyman | Chiacchiere in libertà | 5 | 13-01-2005 20.14.57 |