









Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
Una introduzione alle variabili, tipi primitivi, modificatori di visibilità, metodi statici e normali, e array in Java. Viene inoltre spiegato come dichiarare variabili, il concetto di scope, il casting e la sintassi per la dichiarazione di metodi. Inoltre, viene introdotto l'uso di array multidimensionali e stringhe in Java.
Typology: Study Guides, Projects, Research
1 / 17
This page cannot be seen from the preview
Don't miss anything!










I field hanno come scope l’intero corpo della classe in cui sono dichiarati, compresi i metodi della classe stessa. Quindi sono visibili all’interno di tutti i metodi della classe. Può succedere che una variabile locale in un metodo (oppure il parametro di un metodo) abbia lo stesso nome (identificatore) di una variabile di istanza. In questo caso ha la precedenza la variabile più specifica, cioè la variabile locale o il parametro.
Le variabili di classe infine, comunemente dette anche static field o campi statici , sono variabili di istanza ma nella loro definizione viene usata la keyword ‘static’. static tipo nomeVariabile ; Una variabile di classe è una variabile visibile da tutte le istanze di quell’oggetto ed il suo valore non cambia da istanza ad istanza, per questo appartiene trasversalmente a tutta la classe. Più in dettaglio mentre per le variabili di istanza viene allocata una nuova locazione di memoria per ogni istanza di una classe, per le variabili statiche esiste una unica locazione di memoria legata alla classe e non associata ad ogni singola istanza.
Le variabili di istanza e di classe possono essere ulteriormente qualificate per mezzo delle keywords public e private che ne determinano la visibilità all’esterno della classe in cui sono dichiarate. Private: la variabile sarà visibile (accessibile, utilizzabile per far riferimento al suo indirizzo di memoria e quindi al suo valore) solamente all’interno della classe; Public: la variabile potrà essere utilizzata da qualsiasi parte del codice in cui ci sia una istanza della classe (con la notazione nomeIstanzaClasse.nomeVariabile). Protected la variabile sarà accessibile da ogni altra classe che appartiene al medesimo package della classe che contiene la variabile e da ogni classe che ne deriva (la estende). Se non specifichiamo un qualificatore di visibilità, la variabile sarà lasciata con la visibilità di default che in Java significa che sarà accessibile solo da tutte le classi nel medesimo package.
Infine, si usa la keyword final per dichiarare una variabile che potrà essere inizializzata una sola volta. Al contrario delle costanti, il valore delle variabili final non è necessariamente noto a compile-time ma il loro indirizzo di memoria può essere inizializzato una sola volta. In Java si definiscono costanti le variabili che vengono qualificate contemporaneamente come final e static : è convenzione che i nomi delle variabili final siano in maiuscolo e se il nome è costituito da più parole, queste vengano separate dal carattere underscore (‘_‘);
Java è un linguaggio “fortemente tipato”, perciò i tipi sono fondamentali e c’è uno stretto controllo sull’utilizzo dei tipi: ad esempio non è possibile assegnare un carattere ad un intero, cosa possibile nel linguaggio C, senza un esplicito casting. Il casting consiste nel forzare un valore di un tipo ad assumere un tipo diverso: Esempio: int x=5; float y; y=( float )x; // casting da int a float Lo stesso vale per le operazioni: float risultato= ( float ) x / 3;
Iniziamo da if-else. A volte si tende a chiamare questo costrutto condizionale if-then-else anche se la keyword then non esiste. Lo esamineremo iniziando con il tradurre in Java l’algoritmo che abbiamo scritto in precedenza, in questo modo: if (condizione1) { ... } else if (c ondizione2) { ... } else { ... } Precedenza negli if multipli: Gli if sono valutati in successione e sarà eseguito solamente il primo per il quale la condizione risulterà vera. ‘else’ e ‘else if’ non sono obbligatori.
Pur essendo possibile usare if-else, Java come molti altri linguaggi (il C ad esempio) ammette anche una secondo costrutto condizionale: switch-case. switch (scelta) { case value1: ... break ; ... case valueN: ... break ; default : ... break ; } Tipi e valori
Il ciclo for fornisce una semplice sintassi: una espressione di inizializzazione eseguita solo una volta prima di iniziare il ciclo; una condizione di terminazione (o uscita) dall’esecuzione iterativa. una espressione di ‘aggiornamento’ (tipicamente un incremento) da eseguire al termine di ogni esecuzione del blocco; Con un codice simile al seguente: for (inizializzazione; condizione; incremento) { ... } Il ciclo for ripete un numero di volte prestabilite le istruzioni al suo interno.
Tutti i linguaggi di programmazione forniscono la possibilità di definire, sotto un solo nome, interi gruppi di istruzioni. In questo modo possiamo riutilizzare un blocco di codice in molte parti del programma, semplicemente richiamando il nome con cui l’abbiamo definito, senza dover riscrivere tutto il blocco ogni volta. Questi “blocchi”, a seconda del linguaggio, si chiamano funzioni, procedure, metodi o sottoprogrammi. Sintassi: [public|protected|private] [static] [final] Tipo nomeMetodo( Tipo1 parametro1 , Tipo parametro2 , ..., TipoN parametroN) istruzioni ... return varTipo; } tutte le parti tra parentesi quadre sono opzionali e anche la return è opzionale nel caso in cui Tipo de metodo sia void. Potrebbero non esserci parametri in ingresso. Nella definizione di un metodo, ‘ nomeMetodo’ è il nome assegnato al blocco di codice e che dovrà essere utilizzato per chiamare (eseguire) il metodo;
La sezione [Tipo1 parametro1, ... TipoN parametroN] è detto insieme dei parametri (formali) del metodo in cui si dichiara il tipo ed il nome simbolico delle variabili che il blocco di codice dovrà ricevere dal programma chiamante per poter svolgere il proprio compito.
Per chiamare il nostro metodo all’interno della classe in cui lo stiamo definendo (fuori dalla classe di definizione occorre una sintassi differente), sarà sufficiente scrivere: nomeMetodo( Tipo1 parametro1 , ..., TipoN parametroN); // se è di tipo void oppure tipo nomeVariabile = nomeMetodo( Tipo1 parametro1 , ..., TipoN parametroN);
Il valore specificato accanto a return deve essere del medesimo tipo specificato nella dichiarazione del metodo ma deve essere omesso se il metodo è stato dichiarato come void. Dichiarare un metodo void significa dire che il metodo non ritornerà alcun valore ed in tal caso la keyword return può essere anche omessa.
È importante notare che in Java un metodo è univocamente determinato dalla classe di appartenenza, dal suo nome e dalla lista dei tipi dei parametri che riceve in input. Tutto questo definisce la signature del metodo (la firma) il che significa che siamo liberi di ridefinire il medesimo metodo più volte a patto che ogni definizione abbia una lista di parametri diversa (tipi dei parametri in ingresso, i nomi non contano, non conta nemmeno il tipo di ritorno). In questo modo possiamo sovraccaricare un nome di metodo con diverse definizioni ed effettuare il cosiddetto overloading. Sarà il compilatore a scegliere al momento della chiamata quale metodo utilizzare sulla base del tipo (e del numero) degli argomenti attuali passati.
public : il metodo sarà visibile dovunque private: il metodo sarà visibile solo alla classe protected: il metodo sarà visibile solo dalle classi che stanno nel medesimo package di quella in cui è definito il metodo e dalle classi da essa derivate, default (omissione del qualificatore) implicherà visibilità alle classi nel medesimo package.
Il qualificatore final serve, nel caso dei metodi, per rendere un metodo non ridefinibile dalle sottoclassi: se un metodo viene contrassegnato come final le sottoclassi lo potranno utilizzare e lo erediteranno (quindi lo avranno disponibile) ma non potranno modificarlo.
Tra tutti i qualificatori utilizzabili nella dichiarazione di un metodo quello che più di ogni altro ne modifica il funzionamento è static. Ogni metodo appartiene ad una classe, che è composta da dati e metodi.
Come detto sopra la lunghezza di un array è fissata in fase di creazione e si può in qualsiasi momento accedere al suo valore utilizzando la proprietà length che è presente in ogni array java con la sintassi: n = nomeArray.length;
Java permette anche l’utilizzo di array multidimensionali e la sintassi per la loro dichiarazione ed allocazione si ottiene semplicemente ripetendo le parentesi quadre tante volte quante il numero di dimensioni, per esempio: tipo nomeMatrice [][]= new Tipo [r][c];
import java.lang.String; // per importare la classe String di java
Il modo più semplice e diretto per creare un oggetto di tipo String è assegnare alla variabile un insieme di caratteri racchiusi fra virgolette: String nomeStringa = "Testo..."; questo è possibile in quanto il compilatore crea una variabile di tipo String ogni volta che incontra una sequenza racchiusa fra doppi apici; Oltre a questa modalità, poiché si tratta comunque di oggetti, le variabili di tipo String possono essere inizializzate anche utilizzando la keyword new e un costruttore: String nomeStringa = new String("Testo..."); String nomeStringa = new String();
La classe String espone anche numerosi metodi per l’accesso alle proprietà della stringa sulla quale stiamo lavorando; uno di questi è il metodo length( ) , che ritorna il numero di caratteri contenuti nell’oggetto. La sua sintassi è: int dim = nomeStringa.length(); Stringa = array di caratteri Possiamo pensare a una stringa esattamente come a un array di caratteri , questo significa che possiamo considerare i singoli caratteri come elementi di array. Consideriamo questa stringa: String nomeString = "Ciao, come stai?"; Il carattere 'C' è alla posizione 0, il carattere 'i' è alla posizione 1, ... Per accedere ai singoli caratteri non possiamo usare l’operatore ‘[ ]‘ come negli array, ma possiamo sfruttare il metodo charAt : char charAt( int indice); nomeStringa.charAt(i); // restituisce il carattere della stringa in posizione i
L’operazione di concatenazione di stringhe può essere effettuata in modi diversi. La classe String fornisce il metodo concat per la concatenazione di stringhe la cui signature è: String concat(String str); esempio: String str1 = new String("Nome "); String str2 = new String("Cognome "); String str3 = str1.concat(str2); // assegna a str3 una nuova stringa formata da str1 con str2 aggiunto alla fine; "Nome Cognome". Avremmo potuto ottenere la stessa cosa in modo più semplice utilizzando l’operatore ‘+‘: String str1 = "Nome"; String str2 = "Cognome"; String str3 = str1+str2; oppure String str3 = "Nome" + "Cognome";
Per prelevare e manipolare solo una porzione di una stringa possiamo utilizzare il metodo substring , presente in 2 forme: String substring( int indiceIniziale); String substring( int indiceIniziale, int indiceFinale); La prima ritorna una stringa (sottostringa di quella di partenza) a partire dall’indice specificato fino alla fine della stringa; la seconda invece, ritorna una stringa che è anch’essa sottostringa di quella di partenza, ma che parte dall’indice ‘indiceIniziale’ e termina in ‘indiceFinale’. Per esempio: String titolo = "I promessi Sposi"; String a = titolo.substring(2); // a = "promessi Sposi" String b = titolo.substring(12); // b = "Sposi" String c = titolo.substring(2,9); // c = "promessi"
L’interazione tra diversi oggetti avviene attraverso lo scambio di messaggi : un oggetto, detto sender del messaggio agisce su un altro oggetto, detto recipient , spedendogli uno dei messaggi che il ricevente è in grado di accettare. In altre parole: l’oggetto sender chiama uno dei metodi “esposti” dall’oggetto ricevente. In Java intendiamo per “oggetto” l’istanza particolare di una certa classe, e esso può possedere (o esporre) alcuni metodi. Quindi un oggetto può ricevere un certo messaggio se possiede un metodo che l’oggetto sender è in grado di chiamare (con la opportuna visibilità). In UML lo scambio di messaggi è rappresentato con un diagramma (un semplice schema) chiamato sequence simile a quello riportato in figura: che va letta come: l’oggetto Sender spedisce il messaggio corrispondente al metodo methodXYZ all’oggetto Recipient, il rettangolo vicino alla freccia (sotto Recipient) è comunemente detto activation e rappresenta l’elaborazione necessaria a Recipient per operare sul suo stato e poter reagire al messaggio ricevuto. È naturalmente possibile che, come reazione al messaggio methodXYZ (ad esempio al fine di reperire informazioni per una eventuale risposta al messaggio ricevuto) Recipient operi su altri oggetti generando una cascata di messaggi verso altre entità del sistema (OtherObj nello schema d’esempio).
Una classe è esattamente il “prototipo” di un oggetto in cui vengono definiti tutti i messaggi che ciascuna istanza sarà in grado di ricevere. Nella rappresentazione di una classe sarà quindi importante evidenziare: l’insieme dei metodi che la classe supporta (messaggi ricevibili) l’insieme delle variabili di stato ( attributi ) che ne rappresentano lo stato. Grazie all’UML possiamo utilizzare il Class Diagram come notazione e disegnare una classe in modo simile allo schema che segue: Lo schema mostra sia la notazione per la rappresentazione di una classe (con riportati attributi e metodi) sia quella per rappresentare una istanza.
Nel secondo caso i metodi non hanno ragione di essere riportati. Sono riportati invece i valori degli attributi che sono significativi per ogni singola istanza. Aggiungere dettagli alla rappresentazione Gli schemi sopra riportati vanno considerati solo di primo livello e potranno essere dettagliati aggiungendo per ogni attributo il relativo tipo e valore iniziale: typeAttribute: data_type = initial_valueClass mentre per ogni metodo si dovrà procedere a dettagliare la firma (signature): Metod ( arg: type, …, arg: type ) : return_type Analogamente sia per gli attributi che per i metodi andrà specificata la visibilità che, nella notazione UML, consiste nell’anteporre al nome dei metodi e degli attributi: Segno Tipo di visibilità
~ Java’s package visibility mentre si usa sottolineare (o prefissare con $) i metodi e gli attributi static.
Il costruttore è quel metodo di una classe il cui compito è proprio quello di creare nuove istanze (attraverso la new) , oltre ad essere il punto del programma in cui un nuovo elemento viene creato ed è reso disponibile per l’interazione con il resto del sistema. Il nome del metodo-costruttore deve essere uguale al nome della classe. Esempi sintassi: public NomeClasse(tipo val1, ..., tipo valN){ attr1 = val1; ... attrN = valN; } public NomeClasse(){ ... } In Java possono esserci molteplici costruttori per una medesima classe (ognuno con parametri di diversi) e ne esiste sempre almeno uno. Se infatti per una data classe non viene specificato alcun costruttore, il compilatore ne sintetizza automaticamente uno senza argomenti, detto costruttore default.
Esempio ereditarietà in Java
Con super() si richiama il costruttore della classe estesa.