Docsity
Docsity

Prepara i tuoi esami
Prepara i tuoi esami

Studia grazie alle numerose risorse presenti su Docsity


Ottieni i punti per scaricare
Ottieni i punti per scaricare

Guadagna punti aiutando altri studenti oppure acquistali con un piano Premium


Guide e consigli
Guide e consigli


Programmazione ad oggetti (Java), Teoria, Appunti di Programmazione Java

Spiegazione della programmazione ad oggetti e delle sue caratteristiche, con esempi in Java. Classi e istanze, Package, Convenzioni, Variabili, Tipi Variabile, Costrutti condizionali, Costrutti iterativi (for each), I Metodi, Astrazione (Incapsulamento, Ereditarietà, Polimorfismo, L'override), Le interfacce, Thread e multi-threading, try-catch. In fine Link Utili per il Progetto.

Tipologia: Appunti

2020/2021

In vendita dal 06/03/2021

Informatico-UPO
Informatico-UPO 🇮🇹

4.4

(34)

42 documenti

1 / 52

Toggle sidebar

Questa pagina non è visibile nell’anteprima

Non perderti parti importanti!

bg1
Classi e istanze
Java è un linguaggio puramente Object Oriented e ci impone questo tipo di logica strutturale.
La logica della programmazione ad oggetti si basa su due concetti principali:
Classe: è un'astrazione che rappresenta un insieme di oggetti che condividono le stesse
caratteristiche e le stesse funzionalità.
Oggetto: un oggetto è un’istanza o più precisamente una realizzazione concreta di una classe.
Una classe può essere vista come un contenitore all'interno della quale troviamo due elementi principali:
Gli attributi della classe sono variabili che identificano la classe e che vengono usati dai vari metodi
per compiere qualche operazione.
I metodi sono delle funzioni che espletano un certo compito.
Esempio
Quindi se creerò una classe "Numeri" composta:
due attributi del tipo "numero1" e "numero2"
due metodi "somma" e "sottrazione" che compiono rispettivamente la somma e la sottrazione del
"numero1" e "numero2"
La classe è un'entità a se stante, quindi adesso avremo necessità di istanziare la classe "Numeri" per poi
fare una chiamata al metodo che assegna i valori agli attributi della classe (passando i valori desiderati
come parametri del metodo) ed inseguito i metodi di somma e sottrazione.
Ogni istanza della classe è una realizzazione fisica della classe, quindi le due istanze sono completamente
indipendenti l'una dall'altra e quindi se creiamo due oggetti di tipo "Numeri" e richiamiamo il metodo di
assegnazione passando numeri diversi otterremo due oggetti diversi. Dunque la somma e la sottrazione
relative ai due oggetti saranno generalmente diversi.
Un esempio pratico
Entriamo adesso nel vivo della trattazione spiegando come si creano classi ed oggetti. Creiamo la nostra
classe "Numeri" con due attributi "numeroX" e "numeroY":
public class Numeri {
public int numeroX;
public int numeroY;
}
Come si può vedere un attributo viene dichiarato secondo la sintassi:
ModificatoreDiVisibilità (nell'esempio public), TipoDellaVariabile
(nell'esempio int), NomeVariabile(numeroX e numeroY)
Per quanto riguarda la parola chiave public rappresenta un modificatore di visibilità, ovvero indica che
numeroX e numeroY sono due attributi che possono essere richiamti anche fuori dalla classe.
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34

Anteprima parziale del testo

Scarica Programmazione ad oggetti (Java), Teoria e più Appunti in PDF di Programmazione Java solo su Docsity!

Classi e istanze

Java è un linguaggio puramente Object Oriented e ci impone questo tipo di logica strutturale. La logica della programmazione ad oggetti si basa su due concetti principali:

  • Classe : è un'astrazione che rappresenta un insieme di oggetti che condividono le stesse caratteristiche e le stesse funzionalità.
  • Oggetto : un oggetto è un’istanza o più precisamente una realizzazione concreta di una classe. Una classe può essere vista come un contenitore all'interno della quale troviamo due elementi principali:
  • Gli attributi della classe sono variabili che identificano la classe e che vengono usati dai vari metodi per compiere qualche operazione.
  • I metodi sono delle funzioni che espletano un certo compito.

Esempio

Quindi se creerò una classe "Numeri" composta:

  • due attributi del tipo "numero1" e "numero2"
  • due metodi "somma" e "sottrazione" che compiono rispettivamente la somma e la sottrazione del "numero1" e "numero2" La classe è un'entità a se stante, quindi adesso avremo necessità di istanziare la classe "Numeri" per poi fare una chiamata al metodo che assegna i valori agli attributi della classe (passando i valori desiderati come parametri del metodo) ed inseguito i metodi di somma e sottrazione. Ogni istanza della classe è una realizzazione fisica della classe, quindi le due istanze sono completamente indipendenti l'una dall'altra e quindi se creiamo due oggetti di tipo "Numeri" e richiamiamo il metodo di assegnazione passando numeri diversi otterremo due oggetti diversi. Dunque la somma e la sottrazione relative ai due oggetti saranno generalmente diversi.

Un esempio pratico

Entriamo adesso nel vivo della trattazione spiegando come si creano classi ed oggetti. Creiamo la nostra classe "Numeri" con due attributi "numeroX" e "numeroY": public class Numeri { public int numeroX; public int numeroY; } Come si può vedere un attributo viene dichiarato secondo la sintassi: ModificatoreDiVisibilità (nell'esempio public), TipoDellaVariabile (nell'esempio int), NomeVariabile(numeroX e numeroY) Per quanto riguarda la parola chiave public rappresenta un modificatore di visibilità, ovvero indica che numeroX e numeroY sono due attributi che possono essere richiamti anche fuori dalla classe.

Comandi

Abbiamo adesso creato la classe "Numeri" e la salviamo in un file chiamato "Numeri.java". Compilando adesso il file con il comando javac Numeri.java Così facendo otterremo un file compilato Numeri.class. Adesso potremo essere tentati di mandare in esecuzione il file con il comando java Numeri ma otterremo solamente un messaggio di errore, dato che una classe è soltanto una definizione di una struttura e all'interno della classe che abbiamo scritto non c'è un metodo main nel quale viene istanziata la classe. Definiamo un'altra classe nella maniera seguente e la chiamiamo "Implementazione": public class Numeri { public int numeroX; public int numeroY; } public class Implementazione { public static void main(String args[]){ //Prima istanza della classe Numeri Numeri numeri1; // Istanza numeri numeri1 = new Numeri(); //creazione Oggetti numeri1.numeroX=2; numeri1.numeroY=3; //Seconda istanza della classe numeri Numeri numeri2; numeri2 = new Numeri(); numeri2.numeroX=5; numeri2.numeroY=6; //Mostriamo a video i valori numeroX e numeroY delle due istanze System.out.println(numeri1.numeroX); //Stampa 2 System.out.println(numeri1.numeroY); //Stampa 3 System.out.println(numeri2.numeroX); //Stampa 5 System.out.println(numeri2.numeroY); //Stampa 6 } } La classe "Implementazione" contiene il solo metodo main che costituisce il punto d'inizio per l'esecuzione del programma. All'interno del main saranno presenti:

Convenzioni

Prima di iniziare a scrivere del codice Java è bene apprendere delle piccole regole che stanno alla base per una scrittura di codice pulito:

  • Classe : Indicheremo il nome di una classe sempre con una lettera maiuscola: "Casa". In caso il nome della classe sia composta da più parole indicheremo ogni iniziale della parola con la lettera maiuscola: "CasaInVendita".
  • Metodi : Il nome di ogni metodo di una classe avrà l'iniziale minuscola e se è composto da più parole quelle successive avranno iniziale maiuscola: "restituisciNumeroMetriQuadri".
  • Attributi : valgono le stesse regole espresse per i metodi.
  • Semantica dei nomi : è buona regola dare dei nomi per classi, metodi e attributi che abbiano un significato. Questo permette di leggere il codice di una certa applicazione con minore difficoltà e nel minor tempo possibile. Per esempio, se abbiamo un metodo che esegue la somma tra due numeri se chiamiamo il metodo "somma", una persona che leggerà il nostro codice capirà immediatamente cosa quel metodo esegue e potrà continuare la lettura del codice senza troppi problemi. Nel caso avessimo creato un metodo che esegue la somma e lo avessimo chiamato "sm" ciò avrebbe necessariamente costretto il lettore ad andare a leggersi il codice riguardante il metodo per capirne il funzionamento. Queste buone norme di programmazione non sono elencate nella sola ottica di mettere in grado ad altri di leggere e comprendere rapidamente il vostro codice, ma queste regole servono anche a voi stessi. Immaginate di aver lavorato ad un applicativo di grosse dimensioni con svariate righe di codice e dopo due anni doverci mettere le mani per modificarne alcune parti, sarà sicuramente più immediata la modifica di un applicativo scritto seguendo queste semplicissime

Variabili

Formalmente potremmo definire una variabile in un linguaggio di programmazione come la coppia composta da:

  • un nome simbolico (detto anche identificatore )
  • e un indirizzo di memoria destinato a contenere una determinata quantità, detta comunemente valore della variabile. Ogni variabile ha
  • un nome
  • un tipo
  • alcuni attributi (definiti tramite i modificatori)
  • un contenuto [public|protected|private] [static] [final] Tipo Nome [= valore];

Nome

Nome: è una sequenza di lettere e cifre Convenzione: i nomi delle variabili inizino con una lettera minuscola, e qualora formati da più parole concatenate, tutte le parole successive alla prima siano capitalizzate (e non vengano usati i simboli _ e $). Ad esempio: int nomeDellaVariabileIntera;

Tipo

Il tipo è l’insieme di caratteristiche che qualsiasi valore assunto da una variabile dovrà soddisfare. Il tipo determina :

  • l’insieme dei valori ammissibili (assegnabili)
  • l'occupazione di memoria
  • scope ( l’area del codice nel quale un identificatore resta associato ad un indirizzo di memoria, cioè dalla dichiarazione fino alla fine del blocco)

Tipi Variabile

In Java si distinguono tre tipi di variabili: variabili locali, variabili di istanza e variabili di classe. Vediamo in dettaglio di che si tratta.

  • Le variabili di istanza sono quelle variabili che sono definite all'interno di una classe, ma fuori dai metodi della classe stessa. Le variabili di istanza erano state denominate, all'inizio della trattazione, come gli attributi della classe. public class Numeri { public int numeroX; public int numeroY; } Le variabili di istanza verranno deallocate dalla memoria non appena l'oggetto , istanza della classe, non terminerà di esistere per esempio non appena il flusso dell'applicazione è terminato.
  • Le variabili locali sono tutte quelle variabili che vengono dichiarate ed utilizzate all'interno dei metodi di una classe. public int sottrazione (int x, int y) { int sottrazione; sottrazione=x-y; return sottrazione; } E' importante specificare che la visibilità delle variabili locali è relativa al metodo nella quale viene dichiarata. Per esempio se scrivessi un'altro metodo all'interno della classe e facessi riferimento alla variabile "sottrazione" riceverei un messaggio di errore del compilatore che richiede di dichiare la variabile perchè, per quel metodo, di fatto non esiste. Una variabile locale viene deallocata non appena il metodo effettua il return e quindi ritorna al metodo principale main della classe.
  • Le variabili di classe dette anche static field o campi statici , sono variabili di istanza ma nella loro definizione viene usata la keyword ‘static’. static int var = 6; 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.

Tipi primitivi e valori

Java è un linguaggio tipato, abbiamo già accennato a questo in precedenza, ciò significa che ogni variabile prima di essere utilizzata deve essere dichiarata: dobbiamo quindi assegnarle un nome ed un tipo.

I tipi primitivi in Java

I tipi primitivi in Java sono 8 e ciascuno di essi è pensato per rappresentare un certo tipo di informazione e utilizzando una quantià specifica di memoria. Tipo Q.tà di Memoria Valori Valore di default byte 8 bit da - 128 a 127 incluso 0 short 16 bit da - 32768 a 32767 incluso 0 int 32 bit da - 2147483648 a 2147483647 incluso 0 long 64 bit da - 9223372036854775808 a 9223372036854775807 incluso

0 L

float 32 bit Tipi di dati a Virgola mobile IEEE 754 0.0f double 64 bit Tipi di dati a Virgola mobile IEEE 754 0.0d boolean non specificato, ma sarebbe sufficiente un solo bit serve a rappresentare solamente 2 valori: vero o falso (true o false). false char 16 bit interi senza segno che rappresentano un carattere Unicode = da '\u0000' a '\uffff' \u

wrapper

Ad ogni tipo primitivo corrisponde una cosiddetta classe involucro (wrapper) Tipo primitivo Classe Wrapper byte Byte short Short int Integer long Long float Float double Double char Character boolean Boolean

Casting

È impossibile assegnare un double ad un float, senza un esplicito casting. Il casting consiste nel forzare un valore di un tipo ad assumere un tipo diverso:

ES :

double v1 = 10.0; float v2; int v3 = 5; //ERRORE v2 = (float) v1; // casting v1 = (double) v3;

Boxing (unboxing e autoboxing)

Integer x = new Integer (10); Double y = new Double (5.5); Boolean z = Boolean.parseBoolean("true"); Queste operazioni sono note come operazioni di boxing, cioè “inscatolamento” del tipo primitivo nel relativo tipo wrapper al fine di utilizzare un oggetto e tutte le sue proprietà

L’autoboxing

L’auto-unboxing: dalla tipo wrapper al tipo primitivo Integer x = 10; Double y = 5.5f; Boolean z = true; Number n = 0.0f; Attraverso autoboxing gli oggetti scritti nello spezzone di codice vengono automaticamente creati con i valori di riferimento

L’unboxing

L’unboxing dal tipo primitivo alla tipo wrapper int x = - 1; Integer y = x;

for(int j=0; j<=1; j++) { x[i][j] = i+j; } } for(int i=0; i<=1; i++) { for(int j=0; j<=1; j++) { System.out.println("x["+i+","+j+"] = "+x[i][j]); } } // Proviamo anche con le Stringhe String st[][]={{"riga 0 colonna 0","riga 0 colonna 1"}, {"riga 1 colonna 0","riga 1 colonna 1"}}; // scriviamo a schermo i valori for(int i=0; i<=1; i++) for(int j=0; j<=1; j++) System.out.println("st["+i+","+j+"] = "+st[i][j]); } } Naturalmente abbiamo voluto fare un esempio con solo un Array di due dimensioni, ma come avrete già intuito è possibile sviluppare anche Array di tre o ulteriori dimensioni.

Stringhe

Una stringa è una sequenza di caratteri, come per gli array, le posizioni vanno da 0 a n- 1 Definire una stringa in Java // esempio di oggetto String String OggettoStringa = new String("Valore testuale "); OggettoStringa = OggettoStringa + "dell'OggettoStringa"; System.out.println(OggettoStringa); //Avremo come risultato su schermo "Valore testuale dell'OggettoStringa" perchè abbiamo utilizzato l'operatore + per concatenare le due stringhe.

Esempio:

class ProvaArray2 { public static void main(String args[]) { float numero[] = {2.5f, 4.5f, 8.9f, 5.0f, 8.9f}; // notate la definizione di float con la f come // ultimo carattere del valore float somma = 0.0f; for(int i=0; i<= 4; i++) somma = somma + numero[i]; System.out.println("somma = " + somma) } } In quest'ultimo esempio utilizziamo il ciclo for per sommare tutti i valori dell'Array di numeri float. Il risultato sarà:

somma = 29.

Altro

  • Concatenare le stringhe OggettoStringa = OggettoStringa + "dell'OggettoStringa"; System.out.println(OggettoStringa); //Avremo come risultato su schermo "Valore testuale dell'OggettoStringa" perchè abbiamo utilizzato l'operatore + per concatenare le due stringhe.
  • Estrarre una sottostringa Per prelevare e manipolare solo una porzione di una stringa possiamo utilizzare il metodo substring, presente in 2 forme (overloaded): String substring(int beginIndex); // ritorna una stringa a partire dall’indice specificato fino alla fine della stringa; String substring(int beginIndex, int endIndex); // ritorna una stringa che è anch’essa sottostringa di quella di partenza, ma che parte dall’indice beginIndex e termina in endIndex Per esempio: String titolo = "I promessi Sposi"; String a = titolo.substring(2); // a vale "promessi Sposi" String b = titolo.substring(12); // b vale "Sposi" String c = titolo.substring(2,9); // c vale "promessi"
  • length rilascia il valore della lunghezza di un stringhe. str.length()
  • readSeq(): legge una sequenza di stringhe conclusa dalla stringa vuota e restituisce un array che le contiene tutte (esclusa quella vuota)
  • readSeq(String prompt): come sopra, ma visualizza la stringa prompt a ogni richiesta
  • readSeq(String msg,String prompt): come sopra, ma per prima cosa visualizza la stringa msg
  • Copia di array: System.arraycopy()
  • readString(), readString(String)Metodi per la lettura di valori (jbook.util.Input)
  • Costruttore String(char[]): da array di char a stringa
  • Confronto per uguaglianza: equals()
  • variante: equalsIgnoreCase()
  • Confronto per ordinamento lessicografico: compareTo()
  • variante: compareToIgnoreCase()

Costrutti condizionali

I costrutti condizionali rispondono all’esigenza di eseguire diverse parti di un codice subordinatamente ad una determinata condizione.

if-else

if(condizione1) { //SE condizione ... } else if (condizione2) { //ALRIMENTI SE condizione 2 ... } else {//ALRIMENTI ... }

  • A volte si tende a chiamare questo costrutto condizionale if-then-else anche se la keyword then non esiste.
  • Gli if sono valutati in successione e sarà eseguito solamente il primo per il quale la condizione risulterà vera
  • Le condizioni sono espressioni di tipo boolean Esempio: int a = ...; int b = ...; // OK! if(a == b) { } // NO! Sintassi errata: 'a' è un 'int' e non un 'boolean' if(a) { } // OK! boolean c = ...; if(c) { }
  • I seguenti due snippet sono equivalenti: if(condizione) { System.out.println("Condizione verificata"); } if(condizione) System.out.println("Condizione verificata");

switch-case

switch(c) { //INIZIO case value1: //SE c= ... break; //FINE case value2: //SE c= ... break; //FINE case valueN: //SE c=N ... default: //SE NON VIENE VERIFIACATO NIENTE ... //(in questo caso anche se c=n dato che tra il case N e default non c’è un break) } switch-case : salta alla riga con il valore corrispondente al valore dell’argomento di switch e da quella posizione continua eseguendo tutte le istruzioni senza tener conto i case. break: serve a terminare l’esecuzione di un blocco di programma (più precisamente ogni blocco associato a un ciclo iterativo o uno switch) ed anche se il costrutto switch-case è di gran lunga il contesto in cui lo si vede utilizzato, è sintatticamente corretto utilizzarla anche altrove. (tecnicamente parlando non fa parte del costrutto switch-case ma è spesso utilizzato in connessione ad esso e come abbiamo visto è opzionale) default: La clausola default è opzionale e serve a determinare una porzione di codice che sarà comunque eseguita quando non viene verificata nessuna clausola case

Esempio:

int c = ...; switch (c) { case 1: System.out.print("1 "); case 2: System.out.print("2 "); break; case 3: System.out.println("3 "); case 4: System.out.println("4 "); default: System.out.println("4+"); }

for

Il ciclo for pur servendo come i precedenti ad eseguire ripetutamente un blocco, fornisce una semplice sintassi per accomodare:

  • una espressione di inizializzazione eseguita solo una volta prima di iniziare il ciclo;
  • una espressione di ‘aggiornamento’ (tipicamente un incremento) da eseguire al termine di ogni esecuzione del blocco;
  • una condizione di terminazione (o uscita) dall’esecuzione iterativa. for(inizializzazione; condizione; incremento) { ... } si ottiene un programma che esegue esattamente una volta inizializzazione, esegue poi il blocco, quindi effettua l’incremento, valuta condizione e, se questa risulta vera (true, come al solito condizione deve essere di tipo boolean), esegue di nuovo blocco, alla fine del quale ripete il test e così via.

Esempio

int i=0; while(i < 10) { ... i++; } è identico a: for(int i=0; i<10; i++) { ... }

Cicli infiniti

Si osserva che essendo inizializzazione, incremento e condizione opzionali non è strano trovare casi in cui vengano omesse fino all’estremo: for(;;) { ... } letto anche for-ever o ciclo infinito, poiché la condizione di terminazione è omessa e per default considerata come true (il medesimo comportamento si otterrebbe naturalmente con “while(true) {}“).

for each

for-each (detta for-in) che serve quando cui si voglia eseguire un determinato blocco di codice per ogni elemento di un array. for( Type item : itemCollection ) { ... } prendi uno ad uno gli elementi dell array itemCollection, assegna ciascuno di essi alla variabile item ed esegui per ciascun elemento il blocco (che potrà quindi usare item al suo interno). for-each, le Collection e i tipi generics Anche se parleremo più avanti di “Collection” e “generics”, in questa fase ci basta sapere che si tratta di collezioni di oggetti alle quali si applicano i cosiddetti iteratori per effettuare una scansione di tutti gli elementi. Ecco un esempio pratico di una tipica routine di iterazione degli elementi di un array che utilizzi i tipi generics: Queue queue = new LinkedList(); for(Iterator it = queue.iterator(); it.hasNext(); ) { String tmp = it.next();. Elemento successivo ... } (Senza l’ausilio dei tipi generics la cosa diventa ancora più ardua, poiché bisogna effettuare il cast (su it.next()) con il rischio di un’eccezione a runtime. In realtà, seppure con la miglioria dei tipi generics, questa iterazione non è pulita in quanto ci obbliga a utilizzare una struttura dati (Iterator) che di fatto non utilizziamo.) Come abbiamo visto invece, il ciclo for-each permette una definizione automatica di tutto ciò in un solo comando integrato:(la funzione precedente si può sostituire con) for(String tmp:queue) { ... } (Si tratta quindi di una semplificazione che sicuramente dà dei benefici in termine di migliore codifica ma assolutamente non intacca le prestazioni né in positivo né in negativo.) public class ForeachTest { public static void main(String[] args) { Collection coll = new ArrayList(); // utilizziamo l'array degli argomenti con for-each // e popoliamo la collezione for(String tmp:args){ coll.add(tmp); } // stampiamo la collezione for(String tmp:coll) { System.out.println(tmp); } } }