RISOLTO [Java] Array di oggetti non funzionante

Stato
Discussione chiusa ad ulteriori risposte.

Nozomi

Nuovo Utente
20
2
Buonasera. Da qualche giorno ho iniziato a studiare Java, a breve inizia un corso di formazione e vorrei portarmi avanti con lo studio.

Sto provando a creare un piccolo programmino che mi permetta di inserire titolo, autore e prezzo di tot libri.

Di conseguenza ho creato una classe ed il main che incollo qui di seguito:

Java:
public class Libro {
    private String nome ="ciao";
    private String autore ="bhu";
    private int costo =1;
 
   //costruttore
public Libro (String nome, String autore, int costo)
{
    this.setNome(nome);
    this.setAutore(autore);
    this.setCosto(costo);
}

public String getNome() {
    return nome;
}

public void setNome(String nome) {
    this.nome = nome;
}

public String getAutore() {
    return autore;
}

public void setAutore(String autore) {
    this.autore = autore;
}

public double getCosto() {
    return costo;
}

public void setCosto(int costo) {
    this.costo = costo;
}
}

Java:
import java.util.*;
public class libreria {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner acquisizione = new Scanner(System.in);

        // inizio variabili dell'oggetto
        String nome="nome";
        String autore="autore";
        int prezzo=1;     
        Libro[] volumi;
      
        // fine variabili dell'oggetto
      
        System.out.println("quanti libri vuoi inserire?: ");
      
        int numeroLibri=acquisizione.nextInt();
        volumi=new Libro[numeroLibri];
      
        for (int numeroOggetto=0; numeroOggetto<5;numeroOggetto++)
        {
            System.out.println("Titolo libro?");
            nome=acquisizione.nextLine();
          
            System.out.println("autore?");
            autore=acquisizione.nextLine();
          
            System.out.println("prezzo?");
            prezzo=acquisizione.nextInt();
          
            volumi[numeroOggetto]= new Libro(nome, autore, prezzo);
        }
      
        for (int numeroOggetto=0; numeroOggetto<5;numeroOggetto++)
        {
            System.out.println(volumi[numeroOggetto]);
        }
    }
}

Anche se in maniera ancora elementare, so lavorare su degli oggetti elementari e tutta la trafila del passargli i parametri con metodi e costruttori, ma ora che sto cercando di creare un array di oggetti non riesco a raccapezzarmici, non capisco perchè non riesco ad invocare il metodo .setNome() per passare il relativo parametro, di conseguenza l'oggetto stampato restituisce dei valori assolutamente insensati.

Abbiate pazienza, ho aperto libri/web e tutorial su java solo da 7 giorni

Ringrazio in anticipo chiunque possa illuminarmi e mettermi sulla via giusta.
 
Ultima modifica da un moderatore:

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Ciao!
Prima di tutto un consiglio: evita di dare troppi spazi vuoti (specie nella prima classe).

C'è in realtà qualche errore, ad iniziare dall'inizializzazione delle variabili. Questa deve avvenire nel costruttore.
Il metodo getCosto() restituisce double, ma in realtà costo è definito come intero; in questo caso la variabile viene troncata, e di conseguenza perdi la precisione.

Java:
String nome="nome";
String autore="autore";
int prezzo=1;

Questo non ti serve in realtà. Ti è sufficiente dichiararle ed inizializzarle a null o vuote (le stringhe).

Anche qui c'è un errore:
Java:
        for (int numeroOggetto=0; numeroOggetto<5;numeroOggetto++)

leggi "numeroLibri" elementi ma poi utilizzi come limite il valore 5.

L'errore è causato dal fatto che nextInt() non scarta il carattere di nuova riga; dovresti utilizzare ancora nextLine() per scartare il carattere di nuova riga.

Una soluzione migliore è quella di verificare tramite gli "hasNextXxx()" la presenza di token.
Puoi anche utilizzare next() al posto di nextInt() e parsare il valore, trasformandolo in intero:

Java:
numero = Integer.parseInt(acquisizione.next());

Tuttavia non è sicuro in quanto possono essere lanciate eccezioni.
 

Nozomi

Nuovo Utente
20
2
Ciao, grazie per la risposta e per i consigli.

Quindi

Java:
 for (int numeroOggetto=0; numeroOggetto<5;numeroOggetto++)

diventa

Java:
 for (int numeroOggetto=0; numeroOggetto<numeroLibri;numeroOggetto++)

e fin qui è chiarissimo. Ho corretto il tipo della variabile nella classe.

Non mi è chiaro invece quando dici che dovrei inizializzare le variabili nel costruttore, puoi farmi un esempio? Perchè sicuramente mi sfugge qualcosa.
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Mi riferisco a questo:

Java:
public class Libro {


    private String nome ="ciao";
    private String autore ="bhu";
    private int costo =1;
   
    
public Libro (String nome, String autore, int costo)
{
    this.setNome(nome);
    this.setAutore(autore);
    this.setCosto(costo);
    
    
}

Non è propriamente corretta quell'inizializzazione. Vedo che hai solo il costruttore con i 3 parametri, quindi per creare l'oggetto devi passare i valori, come fai correttamente nel main().
In questo caso puoi scrivere quelle variabili in questo modo:

Java:
public class Libro {

    private String nome, autore;
    private int costo;
   
public Libro (String nome, String autore, int costo)
{
    this.setNome(nome);
    this.setAutore(autore);
    this.setCosto(costo);
}

senza assegnare valori.

Oltretutto le variabili membro della classe (variabili d'istanza, non so come le chiami) vengono già automaticamente inizializzate con valori di default: le stringhe essendo oggetti hanno come valore di default null; le variabili di tipo int, hanno il valore 0.
 

Nozomi

Nuovo Utente
20
2
Ok, corretto ed approfondirò la questione.

Effettivamente

Java:
numero = Integer.parseInt(acquisizione.next());

genera eccezione. In ogni caso, anche passando il prezzo manualmente (quindi dando il valore alla variabile, senza chiederlo all'utente) il programma continua a comportarsi in maniera anomala.

Esempio:

Mi chiede quanti libri voglio inserire (corretto)
subito dopo dovrebbe chiedermi solamente il nome del libro, ma chiede sia il nome che l'autore.
Inoltre, dopo aver inserito i dati richiesti (anche se in maniera assurda, visto l'errore descritto prima), continua a restiture ciò.
Libro@7d4991ad
Libro@28d93b30
Libro@1b6d3586
Libro@4554617c
Libro@74a14482

Mi sa che non è ancora tempo di mettere le mani agli array di oggetti
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Si, perchè tu stampi l'oggetto quando fai questo:

Java:
System.out.println(volumi[numeroOggetto]);

non stai richiamando un metodo della classe. Quando vai a stampare l'oggetto viene usato un codice interno, che è poi il riferimento dell'oggetto.

Tu dovresti richiamare un metodo della classe; un utilizzo comune è l'utilizzo di toString(). E' definito dalla classe Object, e se ne fai l'override, viene richiamato in automatico in situazioni come quella.

Quindi:

Java:
class Libro {

  // blocco riservato alle variabili

  // costruttore

  // metodi della classe

  public String toString() {
    return this->getNome(); // qui puoi fare l'operazione che preferisci
  }

a questo punto quando stampi a video verrà richiamata e tutto funzionerà come ti aspetti.
 

Nozomi

Nuovo Utente
20
2
Chiarissimo!!!

Effettivamente avevo totalmente rimosso che per richiamare il valore passato devo passare per il metodo apposito.

Java:
for (int numeroOggetto=0; numeroOggetto<numeroLibri;numeroOggetto++)
        {
           
            System.out.println(volumi[numeroOggetto].getNome() + 
                               volumi[numeroOggetto].getAutore() +
                               volumi[numeroOggetto].getCosto()
                    );
           
        }

Adesso restituisce i valori di nome e prezzo ma continua a non farmi inserire il valore di Autore.

Eppure non penso di sbagliare qualcosa nell'acquisizione dei 3 valori, o meglio, sicuramente si ma non vedo l'errore.
Continua a chiedermi "Titolo libro" e "Autore" contemporaneamente, facendomi inseire un solo valore. Subito dopo mi chiede quello di prezzo che accetta sereamente.

Secondo il ragionamento di prima, suppongo che cosi sia più corretto il passaggio delle variabili ma continua a farmi saltare l'inserimento di "Autore" o di "Nome", non capisco come mai.



Java:
for (int numeroOggetto=0; numeroOggetto<5;numeroOggetto++)
        {
            
            volumi[numeroOggetto]= new Libro(nome, autore, prezzo);
            
            System.out.println("Titolo libro?");
            volumi[numeroOggetto].setNome(acquisizione.nextLine());
            
            System.out.println("autore?");
            volumi[numeroOggetto].setAutore(acquisizione.nextLine());
            
            System.out.println("prezzo?");
            volumi[numeroOggetto].setCosto(acquisizione.nextInt());
            
            
        
            
        }
 
Ultima modifica:

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
No, in quel modo non è corretto: quando crei l'oggetto passi i parametri, che nel tuo caso sono le variabili vuote (o inizializzate con qualche valore, dipende se le hai modificate); successivamente richiami i metodi set, andando a modificare i valori. Quindi non è esattamente corretto quello che fai.
Dovresti richiamare a quel punto il costruttore senza parametri.

Sicuramente comunque quel nextInt() non pulisce lo stream. La nextLine() ripulisce lo stream rimuovendo il carattere "new line", cosa che non avviene con netxtInt().
 

Nozomi

Nuovo Utente
20
2
Grazie al tuo preziosissimo aiuto (e qualche testata tra tastiera/manuale apogeo, che cambierò al più presto) penso di aver risolto.
Scrivo "penso" perchè per andare va, ma la soluzione mi pare maledettamente poco elegante.

Suppongo che pratiche per risolvere più elegantemente il problema le acquisirò solo con la pratica e lo studio.

Lascio il codice e come ho risolto, in caso altri dovessero trovare questo scoglio.

Java:
import java.util.*;
public class libreria {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner acquisizione = new Scanner(System.in);
    
        // inizio variabili dell'oggetto
        String nome="";
        String autore="";
        int prezzo=1;       
        Libro[] volumi;
        
        // fine variabili dell'oggetto
        
    
        System.out.println("quanti libri vuoi inserire?: ");
        
        int numeroLibri=acquisizione.nextInt();
      [COLOR=rgb(61, 142, 185)]  acquisizione.nextLine();[/COLOR]
        volumi=new Libro[numeroLibri];
        
        
        
        
        
        for (int numeroOggetto=0; numeroOggetto<numeroLibri;numeroOggetto++)
        {
            
            volumi[numeroOggetto]= new Libro();
            
        System.out.println("Titolo libro?");
            volumi[numeroOggetto].setNome(acquisizione.nextLine());
            
            
            
          System.out.println("autore?");
            volumi[numeroOggetto].setAutore(acquisizione.nextLine());
            
            
            System.out.println("prezzo?");
            volumi[numeroOggetto].setCosto(acquisizione.nextInt());
            [COLOR=rgb(44, 130, 201)]acquisizione.nextLine();[/COLOR]
            
            
            
        
            
        }
        
        for (int numeroOggetto=0; numeroOggetto<numeroLibri;numeroOggetto++)
        {
            
            System.out.println(volumi[numeroOggetto].getNome()+
                               volumi[numeroOggetto].getAutore()+
                               volumi[numeroOggetto].getCosto()
                    );
            
        }
        
    
    }

}

Come hai ben fatto notare, nextInt non consuma l'input fino all'ultimo, di conseguenza rimane "invio" in sospeso, ho quindi aggiunto un nextLine() dopo nextInt per consumare quel carattere.

Come dicevo prima, funziona. È poco elegante ma ci lavorerò su.

Grazie ancora per la pazienza e la cordialità :)
 
Ultima modifica:
  • Mi piace
Reazioni: DispatchCode

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Usando hasNextXxx() avresti un controllo maggiore sul contenuto del prossimo token.

Esistono pure alternative a Scanner comunque, come BufferedReader:

Java:
BufferedReader br = new BufferedReader(new InoutStreamReader(System.in));

Inoltre più avanti vedrai che tutti quanti possono lanciare eccezioni, quindi dovrai utilizzare i blocchi try/catch per catturarle.
 

BAT

Moderatore
Staff Forum
Utente Èlite
22,918
11,562
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Piccolo errore di digitazione (colpa di '"o" e "p" che sono vicine sulla tastiera):
new InoutStreamReader(System.in) // NO
new InputStreamReader(System.in) // OK
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Ah grazie per la correzione. Ero da smartphone ;)
 
Stato
Discussione chiusa ad ulteriori risposte.

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!