Eccoci qua, riprendo da dove ero arrivato
xXNicolaXx ha scritto:
Incredibile!! [...]
package aereoporto;
import java.util.ArrayList;
import java.util.Scanner;
public class Registrazione {
Scanner tastiera = new Scanner(System.in);
private String scelta;
Passeggero[] passeggeri = new Passeggero[10];
[...]
public void inserimentoPasseggero() {
for(int i=0; i<passeggeri.length; i++){
System.out.println("Benvenuto! Inserisca il suo nome : ");
String nome = tastiera.nextLine();
System.out.println("Inserisca il suo cognome : ");
String cognome = tastiera.nextLine();
passeggeri[i] = new Passeggero(nome, cognome);
System.out.println("Registrazione avvenuta con successo!");
Passeggero p = new Passeggero(nome, cognome);
gestisciOperazioni();
}
}
[...]
}
Spero sia giusto [...]
Edit: no..no..è sbagliato.. [...]
Ok, ho tenuto solo i passaggi fondamentali.
Prima cosa: le variabili di istanza di Registrazione. Ho già visto che andbin ti ha spiegato che i campi occupano spazio sul heap di memoria. Per ora hai pochissime variabili, e occupano pochissimo spazio, quindi ce ne vuole (ma taaaaaanto ce ne vuole) prima che tu lo esaurisca, tranquillo.
Però devi capire cosa ha senso tenere come campo di istanza e cosa invece non ne ha, per ora è solo una questione di pulizia e di ordine, ma aiuta anche chi legge.
Il vettore passeggeri ha senso che sia un campo di istanza, perché tutti i metodi all'interno di Registrazione devono far riferimento a
quel particolare vettore che tu stai popolando (almeno per come stanno ora le cose). Quindi non avrebbe senso che tu ne creassi uno nuovo ogni volta.
La stringa scelta invece non ha senso di esistere come campo di istanza. E' una variabile comoda all'interno del metodo gestisciOperazioni(), ma altrove non te ne fai nulla. Non è una proprietà di Registrazione, quindi creala solo all'interno di gestisciOperazioni(): anche se la crei più volte non c'è il minimo problema, e quando esci dal metodo sarà cancellata, non stai "sprecando" nulla.
Attento: non ti dico questo perché tu diventi un fanatico della gestione della memoria, nulla del genere, e ovviamente tenere un campo in più o in meno (ma anche parecchie decine di campi) alla jvm cambia relativamente poco (o nulla).
Voglio solo iniziare a farti pensare a cosa deve/conviene che sia un campo dell'oggetto e cosa no.
Ora potresti dire: ma allora perché salvare lo Scanner come variabile di istanza? Una Registrazione non ha come proprietà lo scanner, a me interessa solo che abbia il vettore dei passeggeri per ora.
E' vero, ma dicevo nei primissimi messaggi (è una cosa che ho imparato da andbin tra l'altro ) che ti conviene creare ed utilizzare un solo Scanner all'interno della tua classe. Uno scanner è un oggetto un po' più delicato, non ha molto senso crearne uno nuovo tutte le volte, per ora segui questo consiglio.
Scusa la parentesi noiosa, ma almeno una volta pensavo valesse la pena di farlo, al massimo in seguito ti farò notare cosa potresti togliere, senza troppe chiacchiere .
Ora il punto cruciale del programma, che è il motivo per cui non funziona: non guardo neanche come l'hai corretto per ora,
devi capire perché questo non va bene.
In inserimentoPasseggero() hai creato un ciclo che non deve assolutamente esserci (a meno che non lo volessi fare tu, vedi dopo). Il metodo è fatto per creare ed aggiungere al tuo vettore
un unico passeggero con i dati letti dall'utente, né più né meno.
Il ciclo che hai scritto tu invece ti stampa quei messaggi a video, legge nome e cognome, aggiunge il passeggero creato al posto i del vettore, poi ne crea un altro a caso (non te ne fai più nulla di quel p, non lo stai usando!).
Ma la cosa peggiore è che come ultima istruzione del ciclo richiami il metodo gestisciOperazioni() (che non ha bisogno di essere chiamato se non nel main() la prima volta, te lo ridico dopo).
Stai facendo quindi una ricorsione: quando torni dentro a gestisciOperazioni() il programma "sa" di essere ancora dentro al ciclo in inserimentoPasseggero(), con i=0, quindi anche se tu scegliessi di uscire dal programma, ad esempio digitando 4, il flusso uscirebbe dal do-while (perché la condizione non è più rispettata), ma poi ritornerebbe subito al termine della riga gestisciOperazioni() dentro al ciclo, incrementando i (che diventa pari a 1) e poi ricominciando un altro giro del for.
Se addirittura invece che scrivere 4 nel passo precedente avessi scritto 1, saresti entrato in un nuovo ciclo ancora, e ne avresti due di "aperti".
Capirai che questo è un casino terribile, e sono sicuro che non avevi intenzione di farlo.
Tu non hai bisogno di chiamare gestisciOperazioni() all'interno di inserimentoPasseggero(): quando il programma è nello switch la prima volta che entri nel menù e tu inserisci "1", infatti, lui richiama il metodo inserimentoPasseggero().
Ma quando il metodo termina (immagina per ora che non ci sia quel loop sbagliato) il programma riparte da dove era rimasto prima della chiamata, cioè ora sei a quel "break" all'interno dello switch.
Quell'istruzione termina lo switch e il flusso arriva al controllo della condizione del while, scelta ora vale "1", quindi rientri nel do-while per un altro giro (e così fino a quando scelta rimarrà "1", "2" o "3").
In pratica il programma "si ricorda" dove era rimasto prima di una chiamata, non lo devi riportare tu su gestisciOperazioni(), altrimenti crei un loop infinito (te l'ho spiegato terra-terra senza nominare gli stack e altre cose che conosco poco).
Quindi ora rimuovi quella istruzione gestisciOperazioni() al termine del ciclo. Problema risolto ? No, non ancora!
Senza quell'istruzione quando il ciclo arriva al termine, ricominci subito un altro giro (ne farai dieci in tutto, vista la condizione). Ad ogni giro riempi la cella successiva dell'array fino alla fine.
Ma il metodo deve creare un solo Passeggero, non tutti in una volta! Se invece la tua intenzione era di aggiungere tutti i passeggeri in una volta, parte di quello che ho detto sarà superfluo, me ne scuso
Però in quel caso sarebbe meglio chiamare il metodo assegnaTuttiIPasseggeri, o una cosa del genere, perché il nome è fuorviante e anche il messaggio nel menù.
Ricorda che usare un vettore non vuol dire automaticamente dover usare un ciclo! Il classico (for int i=0;i<passeggeri.length;i++) è solo un modo tradizionale di ciclare un intero vettore per fare un'operazione su tutti i suoi elementi.
Ad esempio per la stampa, il ciclo è quello che ti serve. Ma non vuol dire che sia sempre la cosa da fare...
int[] vettore = new int[100];
vettore[3] = 2;
vettore[6] = 4;
vettore[9] = 6;
vettore[12] = 8;
Io posso benissimo voler assegnare solo alcuni valori al vettore, in questo caso non uso il ciclo. Ma se volessi fare un ciclo con un'unica istruzione, mi sapresti dire come faresti (tanto per farti un esempio in cui si spezza quella dichiarazione del for che ho scritto prima, stavolta i++ non è la migliore scelta, e non solo...)?
Scusami ancora se quello che ho scritto lo sapevi già, ora sarò più sintetico .
xXNicolaXx ha scritto:
Perdona il triplo post..ma finalmente funziona, tranne per una cosa... [...]
public void inserimentoPasseggero() {
for(int i=0; i<passeggeri.length; i++){
cont++;
System.out.println("Benvenuto! Inserisca il suo nome : ");
String nome = tastiera.nextLine();
System.out.println("Inserisca il suo cognome : ");
String cognome = tastiera.nextLine();
passeggeri[cont] = new Passeggero(nome, cognome);
System.out.println("Registrazione avvenuta con successo!");
Passeggero p = new Passeggero(nome, cognome);
gestisciOperazioni();
}
}
[...]
Il fatto che qui mantieni il ciclo anche se assegni il Passeggero alla posizione fornita da cont mi fa pensare che in effetti quella cosa sul ciclo non ti fosse chiara. Per l'uso di cont lo dici già tu in seguito, andiamo avanti.
xXNicolaXx ha scritto:
[...]
Class Bicycle {
int cadence = 0;
int speed = 0;
int gear = 1;
void changeCadence(int newValue) {
cadence = newvalue;
}
void changeGear(int newValue) {
gear = newValue;
}
void speedUp(int increment) {
speed = speed+increment;
}
void applyBrakes(int decrement) {
speed = speed - decrement;
}
void printStates() {
System.out.println("cadence:"+cadence+"speed:"+speed+"gear:"+gear);
}
[...]
Per quanto riguarda la classe Bicycle solo poche cose: speedUp() e applyBrakes() sono dei metodi un po' più elaborati per modificare speed, ma oltre a quello la classe non è proprio standard.
Intanto i campi non sono privati, sarebbe meglio se lo fossero. Diverso sarebbe se la classe dovesse essere estesa, nel qual caso i campi devono necessariamente non essere private (i membri privati non vengono ereditati).
Poi i metodi changeCadence() e changeGear() non sono altro che dei setter e mancano i metodi getter.
Infine printStates() non sostituisce il toString(), quel metodo effettua già la stampa, non restituisce la stringa che rappresenta l'oggetto!
Lo puoi fare, per carità, ma i vantaggi del toString() sono tanti, e ne hai visto solo una parte, quindi perché avere un metodo che lo "scimmiotta" quando puoi ridefinire quello ?
Insisto un po' su questo perché è lo schema che si cerca di "inculcare" a chi inizia a programmare: campi privati e metodi getter/setter. Inoltre nella stessa descrizione del metodo toString() di Object, nel link alla documentazione ufficiale che ti avevo fornito in precedenza, è specificato che si raccomanda alle sottoclassi di ridefinire questo metodo. Questo schema è riconosciuto da tutti, se tu sei in una classe esterna e vedi scritto setSpeed(int value), sai già cosa dovrebbe succedere, se il metodo ha un nome diverso non ne sei sicuro, puoi solo fare ipotesi.
Ma sono convenzioni, non è scritto in nessun testo sacro, almeno credo .
xXNicolaXx ha scritto:
Ora, quello che voglio capire...nella classe bicicletta, non ci sono oggetti, giusto? L'oggetto è quella "cosa" che viene dichiarata con nomeclasse nomeoggetto = new nomecostruttore(parametri), giusto? O forse tutti gli attributi e i metodi della classe Bicycle rappresentano un oggetto però in senso astratto, nel senso che se paragonato alla realtà, la bicicletta è un oggetto e ha quelli stati e funzioni?
Nel nostro caso abbiamo creato l'oggetto "p", che è di tipo passeggero(quindi di tipo passeggero significa che richiama metodi o attributi della classe passeggero? giusto per capire se ho capito).
A questo ha già risposto andbin. E' stato molto specifico, ma mi ricordo che in un altro post proprio lui aveva usato un esempio più figurato che mi era piaciuto molto, spero non gli dispiaccia se lo riprendo
In quell'esempio si paragonava i campi/metodi di una classe come a delle formine che usano i bambini nella sabbia. Quello è lo "scheletro" di come sarà il tuo oggetto una volta creato, quando poi tu scrivi new Nome_Classe() è come se stessi prendendo la sabbia, riempiendo la formina e girandola sulla spiaggia per costruire l'oggetto vero e proprio!
L'oggetto "p" a cui facevo riferimento più in alto è di tipo Passeggero, quindi come hai scritto avrà ( = potrà richiamare su di sè) tutti i metodi della classe Passeggero, e avrà all'interno tutti i campi/attributi (sono più o meno sinonimi in questo contesto) che hai dichiarato sempre in Passeggero.
Il fatto è che p, che hai ancora nel metodo inserimentoPasseggero, continua a essere inutilizzato nel codice. Attento che creare due oggetti Passeggero, anche se con lo stesso nome e cognome, crea due oggetti diversi!
Tu sopra crei un Passeggero che viene assegnato in posizione[cont] all'array passeggeri. Sotto ne crei un altro, p, con lo stesso nome e lo stesso cognome e poi lo lasci lì.
Per tornare all'esempio della spiaggia è come se tu riempissi di nuovo la tua formina o il tuo secchiello di sabbia, e poi lo rovesciassi nel mare (non lo recuperi più in alcun modo, togli quella riga )...
xXNicolaXx ha scritto:
Adesso, proprio mentre scrivevo il messaggio, ho risolto involontariamente il problema che i numeri venivano incrementati di 2 alla volta.
Considera il mio ultimo codice funzionante, che però aveva il problema dei numeri doppi appunto. Ho semplicemente tolto
Passeggero p = new Passeggero(nome, cognome);
che si trovava sotto
System.out.println("Registrazione avvenuta con successo!");
e adesso appunto funziona..però vorrei capire perchè..Come mai creava il problema del numero doppio, se io passavo solo le stringhe nome e cognome nel costruttore? Il numero non lo richiamavo, vero?
ps. il contatore l'ho spostato dopo l'inserimento perchè altrimenti creava il problema che dicevi tu
Eliminare quella riga non cambia niente nel tuo programma, cioè hai solo rimosso (giustamente!!) una riga inutile dal codice, ma non stai modificando in nessun modo l'indice i e il contatore.
Devi ancora sistemare quel metodo