View Full Version : [JAVA] Chiarimento su strutture lineari
Ciao a tutti,
questo è un metodo di una struttura lineare
public void rimuoviUtente(String n) {
Utente p = inizio;
if (p == null)
return;
if (p.nome.equals(n)) {
inizio = inizio.prox;
return;
}
while ((p.prox != null) && (!p.prox.nome.equals(n)))
p = p.prox;
if (p.prox != null)
p.prox = p.prox.prox;
//QUI!
}
public class Utente {
String nome;
String email;
Utente prox;
public Utente(String n, String e) {
nome = n;
email = e;
prox = null;
}
}
Il metodo rimuove correttamente un utente dalla lista. Quello che non capisco è: La nuova lista "p", creata all'interno del metodo, è accessibile solo all'interno del metodo. Perchè non viene copiata dentro this.inizio che è pubblico?
O meglio, siccome il metodo rimuoviUtente viene chiamato dall'esterno e dall'esterno viene letto solamente this.inizio perchè "p" non viene copiato in this.inizio?
La classe e il collaudo funziona correttamente. Ma non capisco come diavolo faccia se non gli aggiungo
this.inizio = p;
Se lo aggiungo dopo viene cancellato il primo nodo della lista e anche l'ultimo. E non capisco il perchè...
Gin&&Tonic
14-06-2011, 12:42
A
Gin&&Tonic
14-06-2011, 12:43
while ((p.prox != null) && (!p.prox.nome.equals(n)))
p = p.prox;
if (p.prox != null)
p.prox = p.prox.prox;
//QUI! ??
devi togliere completamente l'if interno al while , non serve a nulla. La tua "lista utenti" viene già esaminata nodo per nodo dall'istruzione:
while (p.prox != null)
p = p.prox;
}
In altre parole il metodo è questo:
public void rimuoviUtente(String n) {
Utente p = inizio;
if (p == null)
return;
while (p.prox != null) {
p = p.prox;
if (p.nome.equals(n)) {
inizio = inizio.prox;
return;
}
}
}
Non ho capito bene cosa fà questo : Utente p = inizio;
Si, ma non capisco perchè non viene aggiornata la variabile this.inizio, ma solo la variabile locale
Questo ad esempio è un altro pezzo di codice.
Io ragiono così:
- Inizializzo "p" al valore this.inizio. (Prodott inizio è il primo nodo della lista)
perchè non posso scorrere direttamente su this.inizio altrimenti viene cambiato il valore e rimangono con solamente l'ultimo nodo in mano.
- Se è nullo, ovvero se sto al primo nodo, allora aggiungo un nuovo nodo al primo (this.inizio)
(Fin qui ha senso..)
- Poi ciclo i successivi nodi della lista "p"
- Quando si verifica una certa condizione, aggiorno l'attributo "quantità" di "p".
Questo codice funziona (e' un esercizio d'esempio).
Quello che non capisco è come faccia a funzionare se la variabile "p" è una variabile locale!!
Avrebbe più senso se la modifica della quantità fosse stata fatta a this.inizio (come per il primo nodo).
Illuminatemi. Non riesco a venirne a capo! Please
public void aggiornaMagazzino(String c, String d, int q) {
Prodotto p = this.inizio;
if (p == null)
this.inizio = new Prodotto(c, d, q);
else {
while (p.prox != null)
p = p.prox;
if (condizione)
p.quant += q;
}
}
non è che potresti postare i codici completi di tutte le classi? così non si riesce a ragionare
Si, certo. Ecco qui...
public class Magazzino
{
Prodotto inizio;
public void aggiornaMagazzino(String c, String d, int q) {
Prodotto p = inizio;
if (p == null)
inizio = new Prodotto(c, d, q);
else {
while (p.prox != null)
p = p.prox;
if (condizione)
p.quant += q;
}
}
}
public class Prodotto {
String codice;
String desc;
int quant;
Prodotto prox;
public Prodotto(String c, String d, int q) {
codice = c;
desc = d;
quant = q;
prox = null;
}
}
allora il punto è che fai casino con i campi della classe prodotto.
nel paradigma ad oggetti è sempre sconsigliabile lasciare accessibili dall'esterno campi di una classe, e quindi è anche sconsigliabile andarvi ad accedere.
il mio consiglio è di rendere disponibili dei metodi nella classe prodotto che ne accedano ai campi.
ad esempio quando vuoi settare il prossimo prodotto, invece di fare p=p.prox avrai un metodo
public boolean setProx(Prodotto p){
if(this.prox!=null){
this.prox=p;
return true;
}
else
return false;
}
e poi richiami in "magazino" inizio.setProx(p);
ma perchè non usare una List?
Non posso usare List perchè è un esercizio d'esame. La difficoltà è farlo senza List e framework vari.
A parte il fatto di incapsulare this.inizio. Quello è chiaro ma non è un problema ora.
Provo a spiegarmi meglio. Questo codice funziona perfettamente.
Il problema è che non capisco come faccia a funzionare.
se "p" non è nullo viene modificato un valore di un nodo della lista.
Fin qui tutto ok.
Il fatto è che la variabile "p" è locale, quindi dovrebbe morire alla fine del metodo e, subito dopo la modifica della lista, non c'è alcun legame con this.inizio!
Quando vado a stampare l'intera lista (da un altro metodo), ovvero "inizio" non vado a leggere "p"! Ma la lista risulta modificata! Cosa fà??
public class Magazzino
{
Prodotto inizio;
public void aggiornaMagazzino(String c, String d, int q)
{
Prodotto p = inizio;
if (p == null)
inizio = new Prodotto(c, d, q);
else {
while (p.prox != null)
p = p.prox;
if (condizione)
p.quant += q;
}
}
}
tu modifichi però inizio e il campo quantità della classe prodotto, è ovvio che la tua struttura dati ne sarà modificata!
o forse non ho capito bene cosa vuoi dire...
banryu79
16-06-2011, 08:33
...
Il fatto è che la variabile "p" è locale, quindi dovrebbe morire alla fine del metodo e, subito dopo la modifica della lista, non c'è alcun legame con this.inizio!
...
Quando vado a stampare l'intera lista (da un altro metodo), ovvero "inizio" non vado a leggere "p"! Ma la lista risulta modificata! Cosa fà??
...
Ciao x3d0,
credo che tu non abbia ben chiara la distinzione, in Java, tra un'istanza e il riferimento ad un'istanza.
Questa è la dichiarazione di un riferimento ad una istanza di tipo Prodotto con inizializzazione al valore di default:
Prodotto p;
// equivale a:
// Prodotto p = null;
Anche questa è la dichiarazione di un riferimento ad una istanza di tipo Prodotto (con inizializzazione al valore di default):
Prodotto inizio;
// equivale a:
// Prodotto inizio = null;
"p" e "inizio", nei codici qui sopra, sono dei riferimenti inizializzati a null, cioè non si riferiscono (oppure non puntano, non sono collegati, come preferisci) a nessuna istanza di Prodotto.
Se provi ad accedere ad un membro di istanza di Prodotto (ad esempio al membro "codice" così: "p.codice;") tramite uno di questi due riferimenti viene lanciata una NullPointerException.
Come abbiamo detto, "p" e "inizio" sono dei riferimenti. Ma quando entrano in gioco le istanze vere e proprie?
Quando vengono create con la keyword "new".
Qui, ad esempio:
Prodotto p = new Prodotto(c, d, q);
Cosa succede? A sinistra dell'operatore di assegnamento viene dichiarato "p" come un riferimento di tipo Prodotto; a destra dell'operatore di assegnamento viene creata un'istanza di Prodotto.
Il risultato ora è che "p" si riferisce a quell'istanza di Prodotto.
Nota come nel codice un'istanza di per se non ha un nome, è anonima; a venire nominati sono solo i riferimenti alle istanze (in Java).
Un ultimo esempio.
Nel codice che segue immagina che la chiamata a stampa() abbia l'effetto di stampare il nome di ogni riferimento a Prodotto esistente seguito dal valore dei membri dell'istanza di Prodotto a cui è collegato.
Prodotto inizio, p;
// 1)
inizio = new Prodotto("123", "istanza1", 1);
p = inizio;
stampa();
// inizio = ["123", "istanza1", 1]
// p = ["123", "istanza1", 1]
// 2
inizio = null;
stampa();
// inizio = null
// p = ["123", "istanza1", 1]
// 3
inizio = new Prodotto("456", "istanza2", 1);
stampa();
// inizio = ["456", "istanza2", 1]
// p = ["123", "istanza1", 1]
// 4
Prodotto tmp = inizio:
inizio = p;
p = tmp;
tmp = null;
stampa();
// inizio = ["123", "istanza1", 1]
// p = ["456", "istanza2", 1]
// tmp = null
// 5
Prodotto a, b;
a = new Prodotto("789, "istanza3", 1);
b = a;
a.codice = "999";
b.desc = "istanzaX";
stampa();
// inizio = ["123", "istanza1", 1]
// p = ["456", "istanza2", 1]
// tmp = null
// a = ["999", "istanzaX", 1]
// b = ["999", "istanzaX", 1]
La morale è che l'operatore di assegnamento (=) applicato ad un riferimento collega quel riferimento con un'istanza, o indicando l'istanza a cui collegarsi direttamente (il caso del new) o indicandola indirettamente tramite un'altro riferimento.
Cioè l'assegnamento è un'operazione che modifica il riferimento (lo fa puntare ad un'altra istanza) e non tocca le istanze.
Invece l'assegnamento applicato a un membro di istanza attraverso un riferimento a quella istanza (il caso di a.codice = ... oppure b.desc = ..., con a e b che puntano alla stessa istanza) è una mutazione che si applica all'istanza stessa e non tocca i riferimenti (cioè non sono "a" e "b" a venire modificati, ma l'istanza a cui entrambi si riferiscono).
Ora prova ad analizzare nuovamente la classe Magazzino e il suo metodo aggiornaMagazzino: dovresti essere in grado di spiegarci cosa fa, e quindi perchè "funziona" :)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.