appunti java – Capitolo 5 pag. 1 5. Caratteri, stringhe e numeri come oggetti Negli esempi dei precedenti paragrafi si è fatto uso quasi esclusivo di variabili numeriche di tipo int, float, double e char. Questi quattro tipi di dati coincidono con i tipi di dati del Pascal integer, real, char e sono allocati dal programma nella parte statica della memoria. Per questo sono dette variabili di tipo statico in contrapposizione agli oggetti che sono “tipi di variabili” allocate nella parte dinamica della memoria. Le variabili di tipo dinamico di Java (con linguaggio più rigoroso si dovrebbe dire le Classi e gli Oggetti di Java) sono, come si è accennato nell’introduzione, i tipi String, Character, Integer, Float, Double, Boolean. Si nota che nel linguaggio Java, “text sensitive”, tutti i tipi di dati che iniziano con la lettera maiuscola sono Oggetti allocati in memoria dinamicamente. I tipi di dati statici iniziano invece con la minuscola int, long, float, double, char, boolean. 5.1 Allocazione di tipi statici e di oggetti (dinamici) Una variabile dinamica (o Oggetto) è costituita da un indirizzo di memoria che dice al programma dove si trova il dato vero e proprio. Si può anche affermare che un oggetto è costituito da un indirizzo (detto anche link o puntatore) e da un contenuto (dato vero e proprio). Facendo un’analogia potremmo pensare al puntatore come all’indirizzo di casa di una persona e al dato come alla persona vera e propria che vi abita. Per meglio comprendere il significato dei termini statico e dinamico si mostrano in figura le situazioni che si vengono a creare nella memoria RAM del computer quando si dichiarano oggetti invece di variabili statiche. Se in un programma Java si dichiara una variabile statica intera uguale al numero 3 o un oggetto intero 3, si ha la seguente situazione: Dichiarazione: RAM RAM Dinamica o Statica Heap int i; Progr. Java Integer k; i k Var statiche del Progr. Java Assegnazione o Allocazione : i = 3; k = new Integer(3), RAM Statica RAM Dinamica o Heap Progr. Java i k Var statiche del Progr. Java 3 3 #### Si nota che la RAM è divisa logicamente dal compilatore in due parti: quella Statica che contiene il programma eseguibile e le variabili statiche e quella 2 appunti java – Capitolo 5 pag. Dinamica che è usata solo quando il programma invoca il costruttore dell’oggetto (new Integer(3);). Sorgono spontanee alcune domande: Quali sono le ragioni che motivano l’esigenza di oggetti dinamici ? Come si usano gli oggetti dinamici ? Si può trasformare un oggetto dinamico in statico e viceversa ? La programmazione ad oggetti si dovrebbe fondare esclusivamente su Classi e Oggetti definiti dinamicamente. Questa scelta consente una progettazione di componenti complessi (finestre, pulsanti, campi ecc.) che sono utilizzati dai programmi applicativi come mattoni costituenti del linguaggio. Sono come i mattoni del Lego che possono avere diverse forme e utilizzazioni secondo ciò che s’intende costruire. L’uso degli oggetti è quello che si approfondirà nel seguito del paragrafo con diversi esempi. La risposta alla terza domanda e affermativa ed è parte della seconda: ogni Oggetto può essere manipolato solo con apposite operazioni predefinite che si vedranno negli esempi successivi. 5.2 La classe e gli oggetti Character Una Classe in Java è sempre costituita dai seguenti elementi base: Ha un nome (in java l’identificatore inizia con la lettera maiuscola) Ha attributi (campi che contengono i dati che la compongono) Ha uno o più costruttori (operatore con cui si crea nella RAM dinamica lo spazio per il dato) Ha dei metodi (sono gli operatori con cui si manipolano gli oggetti creati con il costruttore) Può appartenere ad una gerarchia di Genitori e Discendenti (Oggetti da cui eredita o fa ereditare attributi e operatori) Può appartenere ad un Package che raggruppa Classi affini La classe Character di Java è così descritta nel manuale (si riportano solo i metodi principali): Nome: Character Attributi: sono le informazioni codificate con l’oggetto (non sempre sono pubblici) Costruttore/i: identificatore Character(char ch); invocazione Character C = new Character( ‘A’ ); effetti crea l’oggetto C e vi alloca la lettera ‘A’ Metodi: si rimanda alla tabella della pagina seguente. Gerarchia: java.lang.Object java.lang.Character Package: java.lang. Note: L’identificatore della classe e del metodo costruttore sono sempre identici. La gerarchia mostra che Character è figlio di Object (che è la madre di tutte le classi Java). Si deve notare che al nome delle classi Object e Character si antepone sempre il nome (minuscolo) del Package cui appartengono (java.lang) appunti java – Capitolo 5 3 pag. Metodi di Character Tipo restituito Identificatore Invocazione: Effetti: Conversione char charValue() ch=C.charValue(); Trasforma l’Oggetto Character C ricevuto in input nel tipo statico char ch in output. Conversione String toString() S=C.toString( ); Trasforma l’oggetto Character C ricevuto in input nell’oggetto String S in output. Confronto int compareTo(Character D) i = C.compareTo(D); Confronta C con D e restituisce in i il valore 0 se sono uguali, negativo se C<D, positivo se C>D. Conversione static char toUpperCase(char ch) ck =Character. toUpperCase(ch); Converte il char ch nel suo maiuscolo ck. Conversione static char toLowerCase(char ch) ck =Character. toLowerCase(ch); Converte il char ch nel suo minuscolo ck. Interrogazione static boolean isDigit(char ch) bo =Character. isDigit(ch); Se ch è alfanumerico restituisce True. Interrogazione static boolean isLetter(char ch) bo =Character. isLetter(ch); Se ch è una lettera restituisce True. Le due righe della tabella (di tutte le tabelle di metodi che seguono) raggruppano rispettivamente, la prima i metodi dinamici che devono sempre essere invocati con un oggetto Character allocato [char ch=C.charValue() ], la seconda i metodi statici che si utilizzano anteponendo il nome della classe Character. [ bo=Character.isDigit(ch) ]. Non è proibito invocare un metodo statico con una variabile oggetto allocata [ Character C=new Character(‘z’); boolean bo=C.isDigit(‘3’); ] ma in questo caso C non svolge alcun ruolo e quindi è più espressivo anteporre Character. La ragione della presenza di metodi statici raggruppati in una classe di oggetti dinamici è di pura comodità. In quale classe collocare una procedura statica che opera su oggetti statici char ? Character pare la più intuitiva anche se le funzioni statiche non operano su Character, sempre di caratteri si tratta. Questa regola di raggruppamento dei metodi statici in una classe di oggetti affini è una caratteristica generale di Java. Esistono anche Classi statiche che vengono utilizzate “strumentalmente” per raggruppare in un unico luogo tutte le funzioni statiche “affini” che lavorano su variabili statiche: la classe Math che illustreremo successivamente è una classe di questo tipo e contiene tutte le funzioni matematiche che operano con numeri di tipo statico. appunti java – Capitolo 5 pag. 4 5.3 La classe e gli oggetti String e StringBuffer Le classi String e StringBuffer sono sequenze di caratteri e differiscono tra loro per alcuni dettagli. La String è un contenitore meno elastico infatti non consente alcune operazioni di cancellazione e inserimento che l’oggetto StringBuffer permette di eseguire agevolmente. Se si devono eseguire operazioni di modifica su una sequenza di caratteri è preferibile usare StringBuffer, se invece sono solo operazioni di analisi è sufficiente la stringa. In ogni caso è sempre possibile trasformare una stringa in un buffer e vice versa. La String Java è così descritta nel manuale : Nome : Attributi: Costruttore/i: Metodi: Gerarchia: Package: String; sono le informazioni codificate con l’oggetto (per esempio lunghezza, e contenuto) identificatori String( ); String(String s); String(StringBuffer buf); invocazione String S = new String( “pera” ); String S= “pera”; { eccezione – equivale alla precedente} effetti crea l’oggetto S allocando la parola “pera” Si rimanda alla tabella della pagina seguente. java.lang.Object java.lang.String java.lang. Note: L’identificatore della classe e del metodo costruttore sono sempre identici. In questo caso esistono molti costruttori solo tre sono riportati qui. L’operatore new NON è necessario: si tratta di un’eccezione nell’uso obbligatorio di new che deve sempre precedere il costruttore. La gerarchia mostra che String è figlio di Object (che è la madre di tutte le classi Java). Si nota che la classe String appartiene allo stesso Package (java.lang). La StringBuffer Java è così descritta nel manuale : Nome : Attributi: Costruttore/i: Metodi: Gerarchia: Package: StringBuffer; sono le informazioni codificate con l’oggetto. identificatori StringBuffer( ); StringBuffer(String s); StringBuffer(int lung); invocazione StringBuffer buf = new StringBuffer( “pera” ); StringBuffer buf = new StringBuffer(100); effetti il primo costruttore crea l’oggetto buf allocando la parola “pera”; il secondo crea un contenitore “vuoto” lungo 100. Si rimanda alla tabella della pagina seguente. java.lang.Object java.lang.StringBuffer java.lang. appunti java – Capitolo 5 5 pag. Metodi di String Tipo restituito Identificatore Invocazione: Effetti: Operazione String concat( String B) S=A.concat( B); S=A+B; Concatenamento di A e B. Operazione String substring(int in, int fin) S=A.substring( in, fin) Estrae da A la sottostringa S, dal carattere di posizione in al carattere fin escluso. Operazione String toLowerCase() S= A.toLowerCase() Trasforma in minuscola la stringa A. Operazione String toUpperCase() S= A.toUpperCase() Trasforma in maiuscola la stringa A Operazione String replace(char old, char new) S = A.replace(old, new) Sostituisce i caratteri di A uguali a old in new. Interrogazione int indexOf(String B) indexOf(char ch) i= A.indexOf (B) i= A.indexOf (ch) Restituisce l’indice di posizione della prima occorrenza della sottostringa B nella stringa A. Idem per il caratteri ch. Interrogazione int length( ) i = A.length( ) Restituisce la lunghezza di A. Conversione char charAt(int ind) ch=C.charAt( ind); Trasforma il carattere di posizione ind della String C nel tipo char ch in output. Confronto int compareToIgnoreCase(String D) i=C. compareToIgnoreCase ( D); Confronta le stringhe C, D restituisce i=0 se C=D, negativo se C precede D, positivo se C segue D. Non tiene conto di Maiuscole o minuscole. Confronto int compareTo(String D) i = C.compareTo(D); Confronta le stringhe C, D restituisce i=0 se C=D, negativo se C precede D, positivo se C segue D. Distingue Maiuscole e minuscole. Conversione static String ValueOf(char ch) (int i) S = String.valueOf( ch ); S = String.valueOf( i ); S = String.valueOf( f ); Converte il char ch nella String S (l’intero i, il reali f ecc…). (float f) appunti java – Capitolo 5 Tipo Identificatore Metodi di restituito StringBuffer 6 pag. Invocazione: Effetti: Operazione StringBuffer append( String S) append( int i ) append( char ch ) Br = Buf.append( S ) Br = Buf.append( i ) Buf.append( S ) Buf.append( i ) Appende all’oggetto Buf la stringa S oppure l’intero i trasformato in letterale ecc. restituisce in Br il risultato (primo caso). Modifica sempre Buf invocante (secondo caso). Operazione StringBuffer delete(int in, int end) Br = Buf.delete( in, end) Buf.delete( in, end) Cancella i caratteri da in a end da Buf e restituisce in Br. Modifica sempre Buf. Operazione StringBuffer deleteCharAt(int ind) Br = Buf.deleteCharAt( ind ) Buf.deleteCharAt( ind ) Cancella il carattere di posizione ind da Buf e restituisce in Br. Modifica sempre Buf. Operazione StringBuffer insert(int offset, String B) Br = Buf.insert(offset, B) Buf.insert(offset, B) Inserisce in Buf la stringa B a partire dal carattere di posizione offset e restituisce il risultato in Br. Operazione StringBuffer reverse() Br = Buf.reverse( ) Buf.reverse( ) Restituisce il buffer in ordine inverso. Modifica sempre Buf. Operazione void setLength(int tot) Buf.setLength(tot) Riduce la lunghezza length() di Buf. Non ha effetto se tot è maggiore di lenth(). Operazione void setCharAt(int ind, char ch) Buf.setCharAt(ind, ch) Sovrascrive ch nella posizione ind di Buf. Conversione String substring( int start) substring( int in, int fin ) S = Buf.substring( start) S = Buf.substring( in, fin) Converte Buf in una String a partire da start o converte il Buf da in a fin in String. Conversione String S= Buf.toString( ) Converte Buf in una stringa Conversione char ch=Buf.charAt( ind); Trasforma il carattere di posizione ind in char. Interrogazione int i = Buf.capacity( ) Restituisce la capacità del buffer i = Buf.length( ) Restituisce la lunghezza effettiva di Buf. toString( ) charAt(int ind) capacity( ) Interrogazione int length( ) Notare che tutte le Operazioni modificano lo StringBuffer invocante cosa che non avviene nei metodi String. In questo caso l’oggetto invocante è restituito in output modificato (parametro di input e output). Nel caso delle operazioni su String l’oggetto invocante è solo un parametro di input. appunti java – Capitolo 5 pag. 7 5.4 La classe e gli oggetti Integer La classe Integer di Java è così descritta (solo metodo principali): Nome : Attributi: Costruttore/i: Integer; sono le informazioni codificate con l’oggetto. identificatori Integer(int i); Integer(String s); ecc. invocazione Integer K = new Integer( 25 ); String s=”25”; Integer K= new Integer(s); { può segnalare un’eccezione se la stringa passata come parametro non è un numero} effetti crea l’oggetto K alloca l’intero 25. Metodi: Gerarchia: Si rimanda alla tabella della pagina seguente. java.lang.Object java.lang.Number java.lang.Integer java.lang. Package: Note: La gerarchia mostra che la classe Integer è figlia di Number a sua volta figlia di Object, e tutte appartengono allo stesso Package (java.lang). La classe Number è una classe genitrice “astratta”; si chiarirà in seguito il significato di questo termine. La tabella dei metodi della classe Integer mostra che le operazioni aritmetiche tra Integer non sono previste. Per eseguirle si rende necessario trasformare gli oggetti Integer in tipi statici int e quindi, dopo le operazioni, se necessario, ritrasformare i risultati in oggetti Integer. La regola vale anche per gli oggetti Float, Double, Long che sono rispettivamente reali in semplice e doppia precisione e interi lunghi. Di seguito alla tabella Integer sono elencate le funzioni matematiche contenute nella classe statica Math. Tali funzioni sono molto usate per eseguire operazioni con i tipi statici int, long, float, double. La classe è una classe statica “strumentale” ovvero che non genera oggetti, ma si limita a raggruppare le funzioni matematiche affini. appunti java – Capitolo 5 Metodi Integer 8 pag. di Tipo restituito Identificatore Invocazione: Effetti: Confronto int compareTo(Integer D) i = C.compareTo(D); Confronta C, D e restituisce i = 0 se C=D, negativo se C < D, positivo se C > D. Conversione float int long floatValue() intValue() longValue() f= A.floatValue( ) i= A.intValue( ) l=A.longValue() Converte l’Integer A nel float f statico oppure in un int o in un long. Conversione String toString() S=A.toString( ) Trasforma l’Integer A nella stringa S. Conversione Static int parseInt(String S) i = Integer.parseInt(String S) Trasforma una stringa in un intero i. Se la stringa non è corretta segnala Eccezione. Conversione Stratic String toString(int i) S = Integer.toString(int i) Trasforma un int in una String. Metodi di Math Tipo restituito Identificatore Invocazione: Effetti: Operazione static float double int abs(float f) abs(double d) ecc r = Math.abs( f) r = Math.abs(d) Restituisce in r float il valore assoluto di f. ecc. Operazione static double cos(double d) sin(double d) tan(double d) sqrt(double d) log(double d) exp(double d) pow(double b, double e) rint(double d) random() double r = Math.cos( d ) float f = (float) Math.cos(d) Funzione coseno, restituisce sempre il double r; per ottenere un float occorre eseguire un cast di tipo (float). Radice Logaritmo in base e Esponenziale Potenza be Troncamento Random 0.0 <= R<1.0 static long round(double d) Arrotondamento appunti java – Capitolo 5 pag. 9 5.5 Esempi d'uso degli oggetti esempio 1 : Si codifichi il seguente problema semplice “costruire un programma che assegni una stringa ad una variabile e la stampi subito dopo l’immissione e successivamente la trasformi tutta in lettere maiuscole e la ristampi”. Richieste: realizzare, quanto richiesto, un unico main() che faccia uso degli opportuni metodi della classe String. Codifica ed esecuzione: Output video: Commento al codice: Si noti che, oltre al costruttore di String, si è fatto uso del solo metodo toUpperCase() predefinito della classe. Si poteva assegnare il risultato alla stessa variabile S, ma non si sarebbe conservata la stringa in caratteri minuscoli. esempio 2 : “Progettare un programma che costruisca tre oggetti Character e assegni a questi le lettere n, e, w, quindi trasferisca i caratteri in una String e la stampi assieme alla sua lunghezza”. Richieste: si realizzi un unico main(), che faccia uso degli opportuni metodi della classe Character e String. Codifica ed esecuzione: appunti java – Capitolo 5 pag. 10 Output video: Commento al codice: Si noti che il costruttore del tipo Character è necessario per creare i tre caratteri. Per assegnare i caratteri alla String è necessario convertirli, a tale fine si è fatto uso, per il primo dei caratteri, del metodo toString() che è un metodo della classe Object. Ogni oggetto ha una rappresentazione in modalità stringa e quindi tale metodo trasforma sempre l’oggetto in una stringa. Per i caratteri successivi è sufficiente l’accodamento con l’operazione di append (+) tra stringhe. Si poteva anteporre una stringa vuota “” e appendere (+) i tre caratteri. esempio 3 : “Costruire un programma che assegni a uno StringBuffer lungo 25 le lettere j, a, v, a, quindi trasferisca i caratteri in una String e stampi la stringa con la relativa lunghezza e il buffer con le rispettive lunghezza e capacità”. Richieste: realizzare un unico main() che faccia uso degli opportuni metodi della classe StringBuffer e String. Codifica ed esecuzione: Output video: Commento al codice: Si noti che è sempre possibile assegnare uno StrungBuffer a una String. In questo caso si è usato il costruttore di StringBuffer che utilizza il parametro dimensione e appunti java – Capitolo 5 pag. 11 quindi opera un assegnamento dei caratteri con il metodo append(). Per convertire in String e sufficiente invocare il metodo toString(). Si noti anche l’utilizzo dei due metodi length() funzionanti sia per String che per StringBuffer; basta cambiare l’oggetto con cui il metodo viene invocato. Il metodo capacity() funziona solo con StringBuffer, infatti String è un oggetto rigido che alloca solo lo spazio necessario a contenere i caratteri e non ha locazioni utili aggiuntive. esempio 4 : “Costruire un programma che assegni a una String una qualsiasi parola quindi inverta l’ordine dei caratteri e la stampi prima e dopo la trasformazione.”. Richieste: risoluzione 4 : realizzare un unico main(), facendo uso degli opportuni metodi della classe StringBuffer e String, quanto richiesto senza usare cicli iterativi di scambio caratteri. Codifica ed esecuzione: Output video: risoluzione 4bis : realizzare un unico main(), facendo uso degli opportuni metodi della classe StringBuffer e String, quanto richiesto usando un ciclo iterativo di scambio caratteri. Codifica ed esecuzione: appunti java – Capitolo 5 pag. 12 Output video: Commento al codice: (soluzione 4) - Si noti che il metodo reverse(), che inverte la sequenza di caratteri, appartiene alla classe StringBuffer e quindi è necessario creare un oggetto String Buffer a cui assegnare la String originale per poter invocare il metodo. (soluzione 4 bis) - Si noti che è indispensabile usare un oggetto StringBuffer per accedere liberamente ai caratteri e modificarli, queste operazioni non sono possibili su oggetti String. esempio 5 : “Costruire un programma che assegni a tre variabili intere statiche (Oggetti) i valori 3,30,300 esegua la somma e la assegni ad una variabile statica intera (Oggetto) e la stampi a video.”. Richieste: risoluzione 5 : realizzare un unico main() usando solo variabili statiche di tipo int. Codifica ed esecuzione: appunti java – Capitolo 5 pag. 13 Output video: risoluzione 5bis : realizzare un unico main() usando esclusivamente Oggetti Integer e metodi relativi. Codifica ed esecuzione: Output video: Commento al codice: (soluzione 5) – La soluzione non ha bisogno di commento in quanto corrisponde alla soluzione che si darebbe in Pascal. (soluzione 5 bis) - Si noti che, oltre ai costruttori, si utilizza il metodo intValue(), che converte un Integer in int. Tale conversione è indispensabile perché le operazioni aritmetiche si possono eseguire (per ragioni di efficienza) solo sui tipi numerici statici e non direttamente sugli oggetti numerici. La lunga istruzione che contiene le conversioni, si incarica di eseguire la somma sui tipi statici e quindi riconverte il risultato in un Integer R con new. appunti java – Capitolo 5 pag. 14 5.E – Esercizi di uso delle classi String, StringBuffer, Integer, Float, Double 5.1 Si desidera costruire un programma che “assegnata una stringa e un carattere determini quante volte il carattere ricorre nella stringa e stampi a video il risultato”. Richiesta: realizzare un solo main( ) che per il conteggio utilizzi i soli metodi di String e Character. 5.2 Si desidera costruire un programma che “assegnata una stringa che contenga sia lettere che numeri determini quante sono le prime e quanti i secondi e stampi a video il risultato”. Richiesta: realizzare un solo main( ) che per il conteggio utilizzi i soli metodi di String e Character. 5.3 Si desidera costruire un programma che “assegnata una stringa che contenga sia lettere che numeri sostituisca tutti i numeri con in carattere ‘x’ e stampi vecchia e nuova stringa a video”. Richiesta: realizzare un solo main( ) che utilizzi i soli metodi di String, StringBuffer e Character. 5.4 Si desidera costruire un programma che “generi in modo random 20 interi compresi tra 0 e 99 e li assegni a un array di Integer. Stampi a video tutte le componenti dell’array e la somma.”. Richiesta: a) realizzare un metodo che generi i numeri e con essi costruisca l’array di oggetti Integer; b) realizzare un metodo che determini la somma e la restituisca in output; c) realizzare il main( ) che invochi nell’ordine i due metodi e successivamente stampi a video quanto richiesto. [Fare uso di oggetti Integer e dei metodi della tabella utili per raggiungere l’obiettivo.] 5.5 Si desidera costruire un programma come il precedente 5.4 con la sola variante di realizzare, invece di un array di Integer, un array di oggetti Double (decimali) generati con la funzione Math.random(). [Nota: Se necessario consultare la documentazione Java della classe Double.] 5.6 Si desidera costruire un programma “simile” al precedente 5.4 che generi e assegni a un array di Number , due oggetti Integer, due Long e due Double e li stampi sul video. [Nota: A differenza degli array in Pascal, in Java è consentito creare array di Oggetti e quindi allocare nelle componenti elementi non omogenei. Questa è una caratteristica tipica della programmazione ad oggetti. Per realizzare il programma si allochi (con new) un array di Number di sei componenti, si generano i sei oggetti indicati e si assegnano all’array.] 5.7 Si desidera costruire un programma che generi un array di dimensione dim<=30 di oggetti Number, immettendo in modo casuale nelle componenti sia Integer compresi tra 1 e 30 sia Double compresi tra 0.00000 e 0.99999 e, infine stampi e verifichi la distribuzione generata. Richieste: rispettare la seguente scomposizione in sottoprogrammi: appunti java – Capitolo 5 pag. 15 scelta() gen_int() main() gen_double() stampa() - main(): invoca dim=gen_int() per generare in modo casuale la dimensione dell’array da allocare, alloca l’array di Number e quindi, invochi ripetutamente la procedura scelta() e, a seconda del numero generato da questa, invocare gen_int() o gen_double() per generare l’oggetto desiderato e assegnarlo alla componente dell’array; infine, invochi la procedura stampa() che mostrerà a video il contenuto dell’array. - scelta(): restituisce casualmente 0 oppure 1. 0 indica la necessità di invocare gen_int() per assegnare un Integer all’array, 1 di invocare gen_double() per assegnare un Double all’array; - gen_int(): genera un int compreso tra 1 e 30; - gen_double(): genera un double compreso tra 0.0000 e 0.9999. - stampa(): stampa l’array. 5.8 Esistono metodi in grado di stabilire di che tipo è un generico oggetto sconosciuto. Ad esempio può essere interessante stabilire se un oggetto Number è un Integer, un Double o un Float. I metodi che operano su oggetti per “interrogarli” e sapere “chi sono” si possono trovare nelle classi Object e Class consultabili nel manuale. La seguente sequenza di istruzioni mostra in che modo: Number N; …………….. // istruzioni che assegnano ad N un Integer …………….. // o un Double in modo casuale Class cl=N.getClass(); // metodo della classe Object. // Restituisce un oggetto classe a cui N appartiene; String nom= cl.getName() // metodo della classe Class. Restituisce una // stringa descrizione della classe. String nom_corto=nom.substring(10,nom.length()); // metodo di String; Al termine dell’esecuzione delle istruzioni le variabili nom e nom_corto restituiranno i seguenti valori. nom conterrà : java.lang.Integer oppure java.lang.Double nom_corto sarà : Integer oppure Double Utilizzando i metodi citati, realizzare un programma come il precedente 5.7 con il compito di stabilire quanti sono gli oggetti Integer e quanti i Double, generati casualmente. Sarà necessarie introdurre una nuova procedura conta() e modificare la procedura stampa() per stampare il semplice messaggio “l’array contiene xx Integer e yy Double”.