RISOLTO Java - primi passi

Stato
Discussione chiusa ad ulteriori risposte.

BAT

Moderatore
Staff Forum
Utente Èlite
22,448
11,351
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Bene.
Nel caso tu stia cercando di usare una libreria esterna (TextIO del libro javanotes8) ti ricordo che essa deve essere importata all'inizio del file e che, per evitare problemi di ricerca dei percorsi, devi inserire il file TextIO.java nella stessa directory dove compili (eventualmente in una subdirectory, dipende da come fai l'importazione). Inoltre, come ti ho anticipato sul forum Majorana, ti ricordo che è possibile evitare di usarla se hai problemi con la lettura dell'input basilare (interi, double, caratteri) usando la classe Scanner.
Per usare tale classe devi innanzitutto importarla con
import java.util.Scanner;
all'interno del main creare un oggetto che legge l'input con
Scanner sc = new Scanner(System.in);
dopodiché puoi usare i suoi metodi per leggere l'input, per esempio per leggere un intero ti basta fare
int numIntero = sc.nextInt();
analogamente ci sono metodi per leggere caratteri, double, stringhe ecc.
Buon proseguimento con Java.
 
Ultima modifica:

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
Inoltre, come ti ho anticipato sul forum Majorana, ti ricordo che
Te ne sei accorto!!! :ok:

Mi sono imbattuto in un errore che non pensavo fosse tale relativamente alla variabili statiche di classe. Non avendolo letto nel libro che sto seguendo (javaniotes8), mi aspettavo che, essendo dichiarate all'interno della classe, fossero riconosciute anche all'interno dei metodi interni alla stessa classe.
Invece il compilatore me le ha riconosciute come non valide. Ho dovuto così spostarle all'interno dell'unico metodo main, che per ora fa tutto. Quindi per usarle anche all'interno dei metodi appartenenti alla stessa classe devo dichiararle public?

A parte ciò, finalmente un passo avanti. Ho compilato finalmente un programmino che sembrava inarrivabile. C'è ancora qualcosa che non va, ma comincia a funzionare:
Codice:
$ javac StringhVert.java
[petrus@localhost java_vari]$ java StringhVert

******* Mostra 3 PAROLE VERTICALI *******
--- le parole sono BENE, BRAVO, BISBIS ---
N A S
E V B
  O I
    S
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 7
	at java.lang.String.substring(String.java:1963)
	at StringhVert.main(StringhVert.java:41)
[petrus@localhost java_vari]$
 

pabloski

Utente Èlite
2,868
916
fossero riconosciute anche all'interno dei metodi interni alla stessa classe.
Quindi per usarle anche all'interno dei metodi appartenenti alla stessa classe devo dichiararle public?

Non dovrebbe essere così. Un metodo non statico di una classe ha accesso a tutte le variabili dichiarate nella stessa classe, siano essere statiche o meno. I metodi statici possono accedere invece solo alle variabili statiche.


A parte ciò, finalmente un passo avanti. Ho compilato finalmente un programmino che sembrava inarrivabile. C'è ancora qualcosa che non va, ma comincia a funzionare:
Codice:
$ javac StringhVert.java
[petrus@localhost java_vari]$ java StringhVert

******* Mostra 3 PAROLE VERTICALI *******
--- le parole sono BENE, BRAVO, BISBIS ---
N A S
E V B
  O I
    S
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 7
    at java.lang.String.substring(String.java:1963)
    at StringhVert.main(StringhVert.java:41)
[petrus@localhost java_vari]$

Evidentemente accedi alla stringa con un for e il for esce dal boundary della stringa, cioè in una stringa di 10 elementi ( numerati da 0 a 9 ) tu stai cercando di accendere all'elemento di indice 10. Ovviamente quell'elemento si troverebbe fuori dalla stringa.
 

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
in una stringa di 10 elementi ( numerati da 0 a 9 ) tu stai cercando di accendere all'elemento di indice 10. Ovviamente quell'elemento si troverebbe fuori dalla stringa.
Infatti era così. ecco ora il risultato finale, corretto ed il sorgente del programmino.
Ora dovrò riprovarlo inserendo variabili da valorizzare con input da tastiera, come l'avevo pensato originariamente.
Codice:
[petrus@localhost java_vari]$ java StringhVert

******* Mostra 3 PAROLE VERTICALI *******
--- le parole sono BENE, BRAVO, BISBIS ---
B B B
E R I
N A S
E V B
  O I
    S

-------------------------------------------------
[petrus@localhost java_vari]$

Non riesco ad allegare il file. Lo copio tutto qui sotto:
// import java.util.Scanner;

/** Il programma legge 3 stringhe e le stampa in verticale,
* l'una accanto all'altra. Le stringhe sono: "gioco", "OCA", "casa"
*/

class StringhVert { /* non necessita di "public" perchè, viene
* assunto tale di default */
//---- elenco variabili della classe ----------------------
// int lunMax = 6;
//----------------------------------------------------------
public static void main (String args[]) { /* modulo di avvio di
* ciascun programma */
int lunMax = 6;
int i;
String crtStr1;
String crtStr2;
String crtStr3;
String str1 = "BENE";
String str2 = "BRAVO";
String str3 = "BISBIS";

System.out.println(); // esegue un'interlinea sulla console
System.out.println("******* Mostra 3 PAROLE VERTICALI *******");
System.out.println("--- le parole sono BENE, BRAVO, BISBIS ---");
int nuSp = lunMax - str1.length(); // n° spazi da aggiungere
for (i = 0 ; i <= nuSp ; i++) {
str1 += " ";
}
nuSp = lunMax - str2.length(); // n° spazi da aggiungere
for (i = 0 ; i <= nuSp ; i++) {
str2 += " ";
}
i = 0;
do {
crtStr1 = str1.substring (i, i+1);
crtStr2 = str2.substring (i, i+1);
crtStr3 = str3.substring (i, i+1);
System.out.println (crtStr1 + " " + crtStr2 + " " + crtStr3);
i++;
} while (i < lunMax);
System.out.println ("-------------------------------------------------");
} // fine modulo "main"
} // fine classe ("StringheVerticali")
 

pabloski

Utente Èlite
2,868
916
La questione delle variabili era relativa il main? Il main può accedere alle variabili statiche della classe, ma non può accedere a quelle d'istanza/non static. Questo perchè main viene chiamato quando la classe non è stata ancora istanziata.

Per esempio si può portare fuori dal main le variabili seguenti

Java:
static String str1 = "BENE";
static String str2 = "BRAVO";
static String str3 = "BISBIS";

rese come static sono utilizzabili dal main, altrimenti dà errore
 

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,207
1,844
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 permetto di aggiungere alcune considerazioni/osservazioni.
Quando nei primi post ti consigliavo di proseguire, era proprio per quel motivo: purtroppo - o per fortuna - in Java ci vuole un pò di teoria prima di comprendere il significato di ciò che stai utilizzando, anche in un semplice hello world.

Mi sono imbattuto in un errore che non pensavo fosse tale relativamente alla variabili statiche di classe. Non avendolo letto nel libro che sto seguendo (javaniotes8), mi aspettavo che, essendo dichiarate all'interno della classe, fossero riconosciute anche all'interno dei metodi interni alla stessa classe.
Invece il compilatore me le ha riconosciute come non valide. Ho dovuto così spostarle all'interno dell'unico metodo main, che per ora fa tutto. Quindi per usarle anche all'interno dei metodi appartenenti alla stessa classe devo dichiararle public?

Immaginavo avessi problemi con le variabili statiche, infatti in un precedente post ho anticipato - o meglio speravo di anticipare - eventuali tuoi quesiti.
Ti ha già risposto pabloski nel merito; aggiungo qualcosa pure io: puoi avere variabili e metodi statici, ma entrambi hanno limitazioni (ancor più i metodi).
Le variabili statiche puoi vederle come "variabili globali", nel senso che non serve creare un oggetto per utilizzarle, ma si accede ad esse specificando il nome della classe.

public, private, protected e "nessuno specificatore" (che è quello che stai utilizzando tu al momento sulla variabile di istanza) indicano la visibilità di una variabile (o di un metodo). Non appena affronterai l'incapsulamento vedrai che regolano unicamente la visibilità all'esterno della classe.
Una variabile o un metodo privati - questo vale in generale con la OOP - indicano che quella variabile/metodo viene utilizzata solo all'interno della classe.
Usando invece public è visibile ovunque, ma è più raro veder una variabile di istanza pubblica rispetto ad un metodo. Questo perchè uno dei principi dell'incapsulamento è la protezione dei dati (le variabili di istanza); ecco perchè si forniscono metodi che agiscono, operano, su di essi - i famosi getter/setter - svolgendo anche operazioni.
protected fa la differenza con i package, ma sono cose che vedrai più in là, è inutile parlarne ora.



Se non mi fossi espresso bene - non uso Java da ormai 2 o 3 anni, ma è stato il primo amore 11 anni fa, anche se la OOP è sempre presente nelle mie giornate - ti lascio anche la doc di Oracle proprio sugli specificatori di accesso: https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html
 

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
Il main può accedere alle variabili statiche della classe, ma non può accedere a quelle d'istanza/non static. Questo perchè main viene chiamato quando la classe non è stata ancora istanziata.

Per esempio si può portare fuori dal main le variabili seguenti

Java:
static String str1 = "BENE";
static String str2 = "BRAVO";
static String str3 = "BISBIS";

rese come static sono utilizzabili dal main, altrimenti dà errore

Restando al mio piccolo esercizio, tu vuoi dire che se io dichiaro:
Codice:
class StringhVert { 
    String str1 = "BENE";
    String str2 = "BRAVO";
    String str3 = "BISBIS";    
    public static void main (String args[]) {    
     --- bla ---- bla ---- bla ----
    System.out.println (str1 + " " + str2 + " " +str3)
   }
le 3 stringhe str1, str2, str3 vengono riconosciute in main, mentre se dichiaro
Codice:
class StringhVert { 
    public static void main (String args[]) {    
     --- bla ---- bla ---- bla ----
    System.out.println (str1 + " " + str2 + " " +str3) 
   }       
  String str1 = "BENE";
  String str2 = "BRAVO";
  String str3 = "BISBIS";    
  }
non vengono riconosciute, pur essendo dichiarate, implicitamente, static?
 

BAT

Moderatore
Staff Forum
Utente Èlite
22,448
11,351
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Non esistono variabili/attributi/metodi "implicitamente statici", non sono static in nessuno dei 2 casi:
dichiarare le 3 stringhe prima o dopo il main non cambia nulla, risultano attributi di classe e non sono statici perché manca la parola static davanti alla dichiarazione.
All'interno di un contesto statico (come il main) non puoi usare variabili/attributi (e metodi) non statici perché essi esistono solo se esiste già un oggetto di classe;
in altri termini per accedere alle stringhe non-statiche da dentro il main, devi prima creare un oggetto di classe StringhVert e poi accedere ai suoi membri con la sintassi ad oggetti (scrivo un codice abbastanza brutto da vedere, per farlo "bene" andrebbero usati metodi getter). In pratica dentro il main dovresti scrivere:
Java:
StringhVert ogg = new StringhVert();
System.out.println(ogg.str1);
System.out.println(ogg.str2);
System.out.println(ogg.str3);
altrimenti l'unica alternativa e' dichiarare tutte le variabili esterne al main come static
 

pabloski

Utente Èlite
2,868
916
non vengono riconosciute, pur essendo dichiarate, implicitamente, static?

beh no, per come sono definite in quei due esempi, non sono affatto statiche

e a runtime saranno create/inizializzate SOLO dopo che sarà stata istanziata la classe, cioè dopo la creazione di un oggetto di quella classe

il problema è che la jvm chiama il metodo main prima di istanziare qualsiasi istanza della classe, appunto lo chiama come metodo statico

quindi all'atto della chiamata del main, quelle tra variabili semplicemente non ci staranno proprio in memoria, il che rende impossibile al main accedere a qualcosa che ancora non è stato creato
 

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
Va bene. Ora ho capito.
Questo spiega perchè dichiarate così come avevo fatto inizialmente io, cioè senza l'indicazione "static", provocavano l'errore nelle righe interne al main. Esse infatti erano semplicemente delle variabili locali della classe; non potevano quindi essere condivise col main.
Penso a questo punto di avere veramente fatto un piccolo passo avanti nei "primi passi" di programmazione java.
Grazie a tutti.
 

pabloski

Utente Èlite
2,868
916
Esse infatti erano semplicemente delle variabili locali della classe; non potevano quindi essere condivise col main.

Solo una precisazione. Le variabili static non sono globali, nel senso che appartengono a tutto il programma. In Java ogni cosa appartiene ad una classe.

Una variabile static è definita "di classe", cioè lo spazio in memoria per allocarla viene riservato nel momento in cui è definita la classe. E tutti gli oggetti ( istanze ) della medesima classe, accedono alla stessa "versione" della variabile.

Le variabili non statiche appartengono invece ad un singolo oggetto della classe. Cioè ogni istanza/oggetto di una classe X possiede una sua copia delle variabili non statiche.
 

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
... usando la classe Scanner.
Per usare tale classe devi innanzitutto importarla con
import java.util.Scanner;
all'interno del mai creare un oggetto che legge l'input con
Scanner sc = new Scanner(System.in);
dopodiché puoi usare i suoi metodi per leggere l'input, per esempio per leggere un intero ti basta fare
int numIntero = sc.nextInt();
analogamente ci sono metodi per leggere caratteri, double, stringhe ecc.
Buon proseguimento con Java.
Benissimo. Ho messo in pratica le tue indicazioni, ma non prima di avere anche letto e riletto l'argomento sul libro javanotes8.
Tuttavia non riesco a compilare il programmino di esercitazione perchè, nell'esempio trovato in javanotes8, il richiamo della classe Scanner avviene dentro il main, mentre io lo faccio dentro un modulo diverso, interno alla stessa classe in cui è è dichiarato il main:
Codice:
import java.util.Scanner;
class StringheVerticali {
...
       public static void main (String args[]) {
        Scanner dig = new Scanner(System.in);
...
        digStringhe (); // chiamata modulo di digitazione stringhe
...
       }
       private static void digStringhe () {    // modulo di digitazione parole
            while(nuCrt > 6)
            {
                String digStri = dig.nextLine();    
...
           }
     }
...
}
ed ecco il risultato della compilazione:
javac StringheVerticali.java
StringheVerticali.java:55: error: cannot find symbol
String digStri = dig.nextLine();
......................... ^
symbol: variable dig
location: class StringheVerticali
1 error
La variabile "dig" creata con l'istruzione "Scanner dig = new Scanner(System.in);" non viene riconosciuta.
Sicuramente non ho saputo referenziarla e, purtroppo, non ho capito come procedere.
 

BAT

Moderatore
Staff Forum
Utente Èlite
22,448
11,351
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Come ex-programmatore dovresti sapere qual è lo "scope" di una variabile: è la porzione di codice dentro cui una variabile è visibile.
Nel corpo della funzione/modulo digStringhe() che hai definito, non esiste nessuna variabile dig, è ovvio che non te la vede!
Se vuoi scrivere una funzione separate per leggere, tanto per dire, un intero, la creazione della variabile di tipo Scanner devi farla dentro tale funzione (ed alla fine del corpo aggiungere una istruzione return -per esempio un intero- che ritorna al codice chiamante il valore dell'input da tastiera).
 

petrusic

Utente Attivo
227
20
CPU
AMD Athlon - X86_64
Scheda Madre
Acer RS780HVF
HDD
SSD PLUS da 240GB (ospita 3 S.O Linux), WDC WD10EFRX-68F da 1000GB (ospita solo archivi dati)
RAM
n.2 DDR" per 2GB
OS
fedora 28 Mate, Ubuntu Mate, Linux Mint 19
Come ex-programmatore dovresti sapere qual è lo "scope" di una variabile: è la porzione di codice dentro cui una variabile è visibile.
Infatti lo so, ma non conosco java. Ho riflettuto, provato e cercato molto relativamente alla classe Scanner ed al suo impiego, ma in tutto quello che ho saputo trovare, compreso il tuo appunto sulla creazione di un oggetto per la gestione dell'input da tastiera, qui, ho sempre letto che detta creazione va fatta dentro il modulo main. Perciò ho immaginato, a torto, che fosse un modus operandi rigorosamente obbligato.

Se vuoi scrivere una funzione separate per leggere, tanto per dire, un intero, la creazione della variabile di tipo Scanner devi farla dentro tale funzione (ed alla fine del corpo aggiungere una istruzione return -per esempio un intero- che ritorna al codice chiamante il valore dell'input da tastiera).
Quindi se devo leggere, con funzione dedicata, un intero o una stringa devo scrivere 2 funzioni distinte ed in ognuna creerò l'oggetto dig, però, dove dovrò acquisire stringhe, lo utilizzerò con:
Codice:
String striMia = dig.nextLine();
quando invece dovrò acquisire numeri interi, lo utilizzerò con:
Codice:
int intMio = dig.nextint();
 

pabloski

Utente Èlite
2,868
916
ho sempre letto che detta creazione va fatta dentro il modulo main.

Non sia mai. Se fosse possibile istanziare classi solo nel main, saremmo alla frutta. Un linguaggio con una simile regola avrebbe ben poca utilità.

Quindi se devo leggere, con funzione dedicata, un intero o una stringa devo scrivere 2 funzioni distinte ed in ognuna creerò l'oggetto dig

E' una possibilità. Oppure si può dichiarare la variabile nello scope che include le 2 funzioni, in modo che entrambe la vedano. Questo dipende dai casi. Scanner non si fa problemi, vuole solo sapere dove sta System.in. Una classe che opera su un determinato file, per esempio, sarebbe folle istanziarla due volte in due punti diversi, con entrambe le istanze attive. Ci ritroveremmo col file aperto due volte e due blocchi di codice che ci vanno a scrivere/leggere sopra indipendentemente. Sarebbe il disastro.

Codice:
String striMia = dig.nextLine();
quando invece dovrò acquisire numeri interi, lo utilizzerò con:
Codice:
int intMio = dig.nextint();

Il bello di Java. Una valanga di metodi per ogni situazione. In altri linguaggi bisogna arrangiarsi anche per poter leggere stringhe, interi e quant'altro dallo standard input.
 
Stato
Discussione chiusa ad ulteriori risposte.

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili