appunti java – Capitolo 6
pag. 1
6. Acquisizione dati da tastiera e sottoprogrammi
Si sarà notato che gli esempi proposti non acquisiscono mai dati da tastiera, ma
solo per assegnamento o generazione random di numeri. Tutto questo è
imputabile al fatto che, per eseguire una acquisizione dati da tastiera, si rende
necessario introdurre le classi di Input e Output di Java. In secondo luogo Java è
un linguaggio utile per realizzare interfacce di input di carattere grafico ovvero è
più semplice acquisire dati in un campo all’interno di una finestra video (vedi
ambiente windows) che non direttamente da console o ambiente DOS come
usualmente opera il Pascal.
Per avere a disposizione la possibilità di acquisire dati da tastiera in modo
interattivo faremo uso in seguito di una Classe Tastiera che contiene tre metodi
con i quali è possibile acquisire da tastiera un dato di tipo String oppure un dato
di tipo int o double.
6.1 L’uso di istruzioni di input da console con la classe Tastiera
I metodi della classe tastiera sono i seguenti:
public static String readString();
public static int readInt();
public static double readDouble();
esempio 1 : Si codifichi il seguente problema semplice “costruire un programma
che acquisisca da tastiera una stringa e la stampi sul video”.
Richieste:
a) realizzare il main() program.
Codifica
public class cap06_es_01 {
public static void main(String arg[]) {
System.out.print("immetti una parola:");
String s=Tastiera.readString();
System.out.println(s);
}
}
Commenti alla codifica
La prima stesura del codice mostra il main che non contiene elementi nuovi, se si
esclude l’invocazione di s=Tastiera.readString(). La chiamata di questo metodo
della classe Tastiera è equivalente all’istruzione Readln(s) del Pascal con la sola
differenza che non è una procedure (è un metodo statico che ha sempre la forma
di una function Pascal).
Si ricorda che per un corretto funzionamento la classe Tastiera (il file
Tastiera.class) deve trovarsi nella stessa cartella del main().
Realizziamo ora il seguente programma :
esempio 2 : Si codifichi il seguente problema semplice “costruire un programma
che acquisisca la dimensione N dall’utente, generi un array di N interi e assegni ad
ogni componente i valori 100, 101 … 100+N-1 e lo stampi”.
Richieste:
a) realizzare il main() program.
appunti java – Capitolo 6
pag. 2
public class cap06_es_02 {
public static void main(String arg[]) {
System.out.print("Numero elementi per il vettore:");
int n=Tastiera.readInt();
int V[]=new int[n];
for (int i=0; i<n; i++) V[i]=100+i;
//Fine generazione vettore
for (int i=0; i<n; i++)
System.out.println("V["+i+"]="+V[i]);
// Fine stampa
}
}
Commenti alla codifica
int n=Tastiera.readInt(); significa che la readInt() non riceve dati di input, (non
ha parametri tra le parentesi), ma restituisce un intero (int) in output. Servirà per
acquisire un numero che corrisponde alla dimensione del vettore da generare nel
main().
Si può notare che l’istruzione int V[]=new int[n]; consente di ‘dimensionare in
corsa il vettore’. A differenza del linguaggio Pascal, i vettori di Java hanno un
comportamento dinamico.
I due cicli for che seguono servono rispettivamente per generare il vettore e per
stamparlo.
6.2 Sottoprogrammi e Parametri in Pascal e in Java
Si è visto che per codificare un sottoproblema in Pascal si utilizza lo strumento
della Procedure e della Function. Tale strumento è utile per stabilire quali dati di
input riceve e quali dati in output deve restituire il sottoproblema individuato. In
Java è definito il concetto equivalente di Metodo e lo si è usato con analoghe
modalità. Per Metodo si intende una funzione (una scatola nera) che riceve dati
di input, dal programma invocante, esegue certe operazioni su un oggetto
predefinito e restituisce al termine, eventuali dati di output al programma che lo
ha invocato. L'interfaccia o intestazione di un metodo Java trova quindi una
corrispondenza nelle intestazioni di procedure o function del Pascal.
Di seguito si cercheranno di individuare criteri per stabilire l'esatta
corrispondenza tra questi strumenti di codifica nei due linguaggi e di
conseguenza permettere di trasformare procedure del Pascal in Metodi di Java.
Nei paragrafi precedenti si è fatto uso di metodi Java statici (static) e di metodi
dinamici il cui diverso funzionamento è stato schematizzato con un diverso
utilizzo della memoria del computer per l'allocazione dei valori assegnati. Si tratta
ora di capire come questi due tipi di strumento possano essere usati
correttamente per risolvere sottoproblemi.
In sintesi si potrebbe dire che un metodo statico corrisponde al concetto di
Function (o procedure) del Pascal, in quanto può essere interpretato come uno
spezzone di codice che riceve dati di input e restituisce risultati in output. La
collocazione dei tre precedenti metodi statici nella classe Tastiera ha un
appunti java – Capitolo 6
pag. 3
significato simile a quello delle UNIT del Pascal. In questo caso la classe Tastiera
non ha alcun Costruttore.
Un metodo dinamico è invece sempre associato ad una Classe che genera
Oggetti, tali oggetti possono essere manipolati solo con l'invocazione di questi
metodi dinamici, in particolare una classe di questo tipo è sempre dotata di un
metodo particolare detto costruttore. Vediamo queste differenze attraverso
esempi.
Il sottoproblema, ormai risolto n volte, che calcola il Massimo Comun Divisore tra
due numeri Naturali potrebbe essere schematizzato con le seguenti intestazioni:
Pascal
Intestazione sottoproblema
Function MCD (a, b :integer):integer;
Esempio di invocazione
Var c:integer;
c:=MCD(12, 18);
Java
public static int MCD( int a, int b);
int c=MCD(12, 18)
Java
public (*)Naturale MCD(Naturale b);
Naturale a, b, c;
a = new Naturale(12);
b = new Naturale(18);
c = a.MCD(b);
(b.1)
(*)Se esistesse la Classe Naturale in Java
(a.1)
Nei tre casi precedenti si può interpretare l'interfaccia di MCD() come una "scatola
nera" che riceve due numeri interi (a,b) e restituisce un risultato intero (c).
a, b
MCD
c
La terza riga della tabella individua un terzo caso puramente teorico, in quanto la
classe Naturale non esiste in Java, ma serve per mostrare che l'invocazione di un
metodo dinamico in Java ha una forma diversa e deve sempre essere chiamato
anteponendo all'identificatore del metodo l'oggetto a cui è associato: in questo
caso è un Naturale.
<oggetto> . metodo( <parametri> );
Se ci si sofferma sul significato dei parametri di invocazione di un metodo si nota
che l'intestazione può avere due forme:
(a) Metodo statico intestazione:
public static <tipo in out> nome_metodo ( <tipo e par. input> );
(a.1) invocazione di metodo statico non associato ad una classe:
ris = nome_metodo(<tipo e par. Input>);
[il metodo statico deve essere codificato nello stesso file del main() ]
(a.2) invocazione metodo statico associato ad una classe:
ris = <nome Classe>.nome_metodo(<tipo e par. Input>);
[il metodo statico è codificato nel file della Classe: <nome Classe>]
(b) Metodo dinamico intestazione:
public < tipo par. out > nome_metodo ( <tipo e par. input> );
appunti java – Capitolo 6
pag. 4
(b.1) invocazione metodo dinamico
ris = <Ident. Oggetto>.nome_metodo(<tipo e par. input>);
[il metodo dinamico è codificato nel file della Classe che ha un costruttore per
l’Oggetto]
Quali sono nei due casi (a) e (b) i parametri di input e quelli di output ?
Nel metodo statico non associato ad una classe (a.1) l'invocazione è analoga a
quella di una Function del Pascal. I parametri di input sono tutti e solo quelli che
compaiono entro le parentesi tonde (<tipo e par. input>), quelli restituiti devono
sempre comparire raggruppati in una unica variabile (eventualmente strutturata)
il cui tipo viene dichiarato davanti all'identificatore del metodo <tipo par. out>.
Nel metodo statico associato ad una classe (a.2) ) l'invocazione richiede che si
anteponga all'identificatore del metodo la corrispondente class di Java <nome
Classe>.
I parametri di input di output sono esattamente gli stessi caso (a.1).
I metodi usati negli esempi precedenti:
String s=Tastiera.readString();
Int n=Tastiera.readInt();
erano del tipo (a.2), ossia si trattava di due metodi statici codificati nel file della
classe Tastiera.
Nel metodo dinamico, sempre associato a una classe (b.1) l'invocazione richiede
che si anteponga all'identificatore del metodo un oggetto <oggetto> allocato in
precedenza con new.
I parametri di input sono tutti quelli che compaiono entro le parentesi tonde, a
cui si deve aggiungere l'oggetto con cui è invocato. Quelli di output sono quindi
identici a quelli del precedente caso (a.1).
I metodi di String e StringBuffer del capitolo precedente:
String A=new String(”pippo”);
String S = A.substring(int, int);
riceve in input A che contiene la parola “pippo” e i due parametri di tipo int,
restituisce in output la sottostringa S.
Risolviamo ora un sottoproblema per mostrare le analogie e le differenze tra
Pascal e Java, proponendo le diverse modalità java oltre alla modalità pascal.
esempio 3. Si desidera realizzare un sottoprogramma “che determini la prima e
l'ultima occorrenza di un carattere in una stringa assegnata”
Richieste:
a) risolverlo codificando procedura e main di invocazione in un unico file
Pascal prova.pas.
b) risolverlo codificando metodo statico e main di invocazione in un unico file
Java di nome pro_3_6_uno.java.
c) risolverlo codificando il metodo statico in una classe “contenitore” chiamata
OpString, il main di invocazione è contenuto nel file pro_3_6_due.java.
d) risolverlo codificandolo come metodo dinamico in una classe chiamata
Stringa estensione della classe String di Java, il main di invocazione è
contenuto nel file pro_3_6_tre.java.
appunti java – Capitolo 6
Soluzione a) : Codifica Pascal
pag. 5
Program prova;
Var p,u : integer;
procedure pri_ult(s : string; ch : char; Var p,u : integer);
Begin (* codice omesso *) end;
Begin (* main program *)
pri_ult('banana', 'a', p,u);
writeln(p," ", u);
readln;
end.
Soluzione b) : file java cap06_es_03uno.java
Per risolvere questo problema in java è indispensabile una classe Coppia
ausiliaria che verrà codificata nel file Coppia.java.
Tale classe si rende necessaria in quanto qualsiasi metodo statico e dinamico di
Java restituisce un solo Oggetto e quindi senza un “Oggetto Coppia” non sarebbe
possibile restituire due numeri interi.
Primo file Coppia.java (necessario in tutte le soluzioni java)
public class Coppia {
private int p, int u;
// l’oggetto Coppia ha come attributi 2 interi
public Coppia(int a, int b) { p=a; u=b; } //Costruttore di una coppia;
public void stampa(){ // Metodo che consente la stampa di una Coppia
System.out.println(p+" "+u);
}
}
Secondo file cap06_es_03uno.java
Il codice della classe di cap06_es_03uno.java deve contenere sia il main() che il metodo
statico pri_ult() come segue:
public class cap06_es_03uno {
public static Coppia pri_ult((String s, char ch) { // codice }
public static void main(String arg[]){
coppia c;
c = pri_ult("banana", 'a' ); (modalità di invocazione a.1)
c.stampa();
(modalità di invocazione b.1)
}
}
Soluzione c) : file java cap06_es_03due.java
Per risolvere questo problema in java si deve costruire una ulteriore classe
contenitore di nome OpString.java che conterrà il solo metodo statico pri_ult().
Rimane indispensabile la classe Coppia ausiliaria già codificata nel file
Coppia.java.
Codifica cap06_es_03due.java
Il metodo statico pri_ult() è contenuto nella sottostante classe contenitore:
public class OpString {
public static Coppia pri_ult((String s, char ch) { // codice }
}
appunti java – Capitolo 6
pag. 6
Il codice di cap06_es_03due.java deve contenere SOLO il main()
public class cap06_es_03due {
public static void main(String arg[]){
coppia c;
c = OpString.pri_ult("banana", 'a' ); (modalità di invocazione a.2)
c.stampa();
(modalità di invocazione b.1)
}
}
Soluzione d) : file java cap06_es_03tre.java
Per risolvere questo problema in java si deve costruire una ulteriore classe
Stringa.java sottoclasse di String che conterrà il solo pri_ult() che non è più
statico. Rimane indispensabile la classe Coppia ausiliaria già codificata nel file
Coppia.java.
Codifica cap06_es_03tre
Il metodo pri_ult() non è più statico ma è contenuto nella sottostante classe Stringa
sottoclasse di String:
public class Stringa extends String {
public Stringa(String s) { super String(s); }
// Costruttore di un oggetto Stringa. E’ una String Java
public Coppia pri_ult( char ch) { // codice }
// metodo dinamico applicabile a un oggetto Stringa
// l’invocazione Stringa S=”pippo”; Coppia c=S.pri_ult(‘p’);
// è il modo in cui si passano i due parametri Stringa e char
}
Il codice di cap06_es_03tre.java deve contenere SOLO il main()
public class cap06_es_03tre {
public static void main(String arg[]){
coppia c;
Stringa S=new Stringa(”banana”);
c = S.pri_ult('a');
(modalità di invocazione b.1)
c.stampa();
(modalità di invocazione b.1)
}
Si nota che un metodo statico o dinamico restituisce sempre un solo tipo di dato
e si rende di conseguenza sempre necessario definire il tipo di dato da restituire
se questo è strutturato. Nel caso particolare, siccome devono essere restituiti due
interi, si dovrà dichiarare una classe Coppia che diviene il contenitore unico dei
due valori restituiti in output dal metodo.
Anche in questo caso i tre sottoproblemi Java possono essere interpretati dalla
seguente "scatola nera"
s, ch
c
Pri_ult
c non è più un tipo semplice ma è costituito dalla coppia (c.p,c.u).
Un ulteriore sottoproblema che “elimini un carattere di posizione assegnata in una
sequenza di caratteri” ha le seguenti intestazioni:
Pascal
Intestazione sottoproblema
Function deleteCharAt(s:string;ind:integer):string;
Esempio di invocazione
Var sr:string;
sr :=deleteCharAt(‘fico’,3) ;
appunti java – Capitolo 6
Pascal
Java
Java
pag. 7
Procedure deleteCharAt (Var s:string; ind:integer);
Var s:string; s:=’fico’;
deleteCharAt(s,3);
public static StringBuffer deleteCharAt (StringBuffer StringBuffer sr,s ;
s, int ind)
s=new StringBuffer(‘fico’) ;
sr=deleteCharAt(s,3); (a.1)
public StringBuffer deleteCharAt (int ind) (*)
StringBuffer sr,s ;
s=new StringBuffer(‘fico’) ;
(*)metodo presente in StringBuffer
sr=s.deleteCharAt(ind);
6.E - Esercizi
[di conversione di intestazioni da Pascal a Java static e loro prova]
6.1. Si è realizzato un programma Pascal che “genera un array di interi compresi tra –100 e 100 in
modo random, di dimensione N con 1<=N<=Dim (Dim=20) e ricerca un intero X nell’array
assegnato dall’utente, infine stampa il messaggio X esiste/NON esiste nell’array”. La struttura del
main() Pascal e le procedure realizzate sono le seguenti:
program es_pascal_6_1;
Type Vett=array[1..20] of Integer;
Var N,X:Integer; A:Vett;
Procedure genera(Var V:Vett; Dim, vmin, vmax :integer );
Begin (* codice *) End;
(*genera il vettore di interi*)
Function ricerca(V:Vett, Dim:Integer; X:Integer):boolean;
Begin (* codice *) End;
(*Ricerca X nel vettore e restituisce true o false*)
Procedure stampa(V:Vett, Dim:Integer);
Begin (* codice *) End;
(*stampa il vettore di interi per verificare*)
Begin (* main *)
Write(‘inserisci il numero di elementi da generare N=”);
readln(N);
Write(‘inserisci l’elemento da cercare nell’array X=”);
readln(X);
genera(A,N,-100,100);
stampa(A,N);
if (ricerca(A,N, X)) Writeln(X,’ Esiste.’) else Writeln(X,’ NON Esiste.’);
readln;
end.
Richiesta: realizzare gli equivalenti metodi statici java e il main() equivalente adeguando i
parametri, il tutto in una unica Classe Java. FARE uso della classe Tastiera.
6.2. Si è realizzato un programma Pascal che “genera due array di interi compresi tra –100 e 100 in
modo random, la dimensione degli array è N1 ed N2 con 1<=N1 ed N2<=Dim (Dim=20), crea
l’array unione dei due array generati e li stampa tutti”. La struttura del main() Pascal e le procedure
realizzate sono le seguenti:
program es_pascal_6_2;
Type Vett=array[1..40] of Integer;
Var N1,N2:Integer; A,B:Vett;
Procedure genera(Var V:Vett; Dim, vmin, vmax :integer );
Begin (* codice *) End;
(*genera un vettore di interi*)
Procedure fondi(V1, V2:Vett, Dim1, Dim2:Integer; Var V:Vett;
DimV:Integer);
Begin (* codice *) End;
(*fonde i due vettori V1 e V2 in V*)
Procedure stampa(V:Vett, Dim:Integer);
Begin (* codice *) End;
(*stampa il vettore di interi*)
Var
appunti java – Capitolo 6
pag. 8
Begin (* main *)
Write(‘inserisci il numero di elementi del primo array N1=”);
readln(N1);
Write(‘inserisci il numero di elementi del secondo array N2=”);
readln(N2);
genera(A,N1,B,N2,-100,100);
stampa(A,N1);
stampa(B,N2);
fondi(A,N1, B, N2, C, N);
stampa(C,N);
readln;
end.
Richiesta: realizzare gli equivalenti metodi statici java e il main() equivalente adeguando i
parametri il tutto in una unica Classe Java. FARE uso della classe Tastiera.
[Di conversione di codici di procedure Pascal in metodi statici Java raggruppati in
una classe “Contenitore” esterna. (Equivalente a una Unit del Pascal) e loro prova.]
6.3. Si desidera tradurre la seguente Unit realizzata in Pascal usando il tipo
String di java.
Unit Stringa;
Type Stringa=String;
interface
function inverti(Stringa S):Stringa;
(* inverte la stringa *)
function conta(Stringa S; ch:char) : Integer;
(* conta quanti ch ci sono in S*)
implementation
function inverti(String S):String;
Begin (* codice *) End;
function conta(Stringa S; ch:char) : Integer;
Begin (* codice *) End;
Begin end. (* fine Unit*)
Program es_pascal_6_3;
Uses Stringa;
Var S:Stringa; ch:char;
Begin
S:=’pippo’; ch=“p“;
Writeln(inverti(S));
Writeln(conta(S,ch));
Readln;
End.
Richiesta: realizzare gli equivalenti metodi statici java inserendoli in una classe Java esterna
chiamata Stringa e realizzare un main() equivalente inserendolo in un diverso file. Adeguare i
parametri dei metodi.