Estratto del documento

Riassunto Programmazione ad Oggetti

Dennis Rapaccini

27 gennaio 2022

Indice

1 Paradigmi di Java 3

1.1 Complilazione, interpretazione e JVM . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3

1.1.1 Gestione della memoria nella JVM . . . . . . . . . . . . . . . . . . . . . . . . . . 4

1.1.2 Riferimenti e valori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.1.3 Memoria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5

1.2 I tre paradigmi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2.1 Incapsulamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2.2 Ereditarietà . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

1.2.3 Polimorfismo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Classi 7

2.1 Costruttore . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

2.2 Parola chiave this . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3 Metodi e classi in dettaglio 7

3.1 Metodi ausiliari . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7

3.1.1 Cosa succede quando si invoca un metodo? . . . . . . . . . . . . . . . . . . . . . 7

3.2 Costrutto for-each . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3.3 Overloading (sovraccarico) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3.3.1 Overloading di metodi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3.3.2 Overloading di costruttori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8

3.4 Parola chiave static . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9

3.5 Parole chiave final . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

3.6 Vararg . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

4 Ereditarietà 10

4.1 Fondamenti di ereditarietà . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

4.1.1 Accesso di membri ed ereditarietà . . . . . . . . . . . . . . . . . . . . . . . . . . 11

4.2 Utilizzo di super . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

4.2.1 Utilizzo di super per chiamare i costruttori della superclasse . . . . . . . . . . . . 11

4.2.2 Secondo utilizzo di super . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11

4.3 Overriding (sovrapposizione) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12

4.3.1 Perché fare l’overriding dei metodi . . . . . . . . . . . . . . . . . . . . . . . . . . 13

4.4 Ereditarietà e controllo dei tipi . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

4.5 Classi astratte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13

4.6 Utilizzo di final con l’ereditarietà . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

4.6.1 Utilizzo di final per impedire l’overriding . . . . . . . . . . . . . . . . . . . . . . 14

4.6.2 Utilizzo di final per impedire l’ereditarietà . . . . . . . . . . . . . . . . . . . . . . 15

4.7 La classe Object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

1

5 Package e interfacce 15

5.1 Package . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

5.2 Protezione dell’accesso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15

5.3 Interfacce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

5.3.1 Definizione di un’interfaccia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16

5.3.2 Implementazione di interfacce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

5.4 Interfacce vs Classi astratte . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

6 Gestione delle eccezioni 17

6.1 Basi sulla gestione delle eccezioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

6.2 Tipi di eccezioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

6.3 Eccezioni non intercettate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

6.4 Utilizzo di try e catch . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

6.4.1 Visualizzazione della descrizione di un’eccezione . . . . . . . . . . . . . . . . . . . 18

6.5 Clausole catch multiple . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

6.6 Dichiarazioni try annidate . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18

6.7 Throw . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

6.8 Throws . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

6.9 Finally . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

6.10 Creazione di sottoclassi di eccezioni . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

7 Strutture dati 20

7.1 Classe Vector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

7.2 Collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20

7.2.1 Iteratori . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

7.3 HashMap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

8 Input/Output 22

8.1 Fondamenti su I/O . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

8.2 Lettura e scrittura di file . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22

8.2.1 Input/Output bufferizzato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

8.2.2 Input/Output formattato . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

8.2.3 Serializzazione degli oggetti . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24

9 Javadoc 25

10 JSON 25

11 API 26

11.1 Postman . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

12 Maven 26

13 Framework 26

13.1 Spring Boot . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26

13.2 JUnit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

13.3 JNI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27

14 Definizioni comuni 28

2

1 Paradigmi di Java

1.1 Complilazione, interpretazione e JVM

Il linguaggio Java si basa su un approccio che combina compilazione (in bytecode) e interpretazione

(del bytecode).

Il bytecode può essere visto come l’assembly di una macchina virtuale, un calcolatore (com-

puter) ipotetico che ha le caratteristiche simili (semplificate) a quelle delle architetture hardware più

comuni.

Il bytecode è un linguaggio di basso livello (tipo assembly) e non è legato ad una particolare architet-

tura hardware.

L’interprete del bytecode è dette Java Virtual Machine (JVM). Il bytecode non è un codice diret-

tamente eseguibile, ma è un codice per una macchina virtuale (cioè un interprete) che si incarica

dell’esecuzione effettiva.

Le classi compilate in bytecode sono portabili su qualsiasi macchina per cui esista una macchina

virtuale Java (JVM).

Il programma finale viene assemblato a runtime (cioè il linking delle classi) e dipende dall’ambiente di

esecuzione.

Perciò si possono costruire programmi indipendenti dalla piattaforma hardware e software (purché

esista una macchina virtuale) e le classi compilate in bytecode assomigliano a componenti software

ricombinabili a piacere.

La macchina virtuale Java esegue come prima cosa il metodo main della classe di bootstrap.

Quindi:

• Compilatore: un programma che prende in input il programma sorgente e produce in output

il corrispondente programma in linguaggio macchina, eseguibile successivamente dal computer.

• Interprete: un programma che prende in input il programma sorgente, traduce un comando

per volta e lo esegue man mano. 3

Approfondimento: Compilazione e interpretazione

Linguaggi come il C, C++, Delphi, Visual Basic sono linguaggi compilati e seguono

questi passi: si scrive il codice in un editor, al più utilizzando un ambiente di sviluppo IDE che

ne facilita la creazione, questo codice viene poi controllato per verificare che non ci siano errori

e poi viene compilato, ovvero ogni istruzione viene trasformata nel corrispondente codice in

linguaggio macchina che può essere, cosı̀, eseguito dal processore; questi sono i linguaggi com-

pilati che vengono detti anche linguaggi imperativi, ed hanno il vantaggio di prestazioni migliori.

I linguaggi interpretati, invece, seguono una strada diversa, il codice sorgente viene, ap-

punto, interpretato al volo e vengono, quindi, eseguite le istruzioni cosı̀ come descritte nel

codice sorgente; un esempio su tutti è il PHP il cui codice viene “elaborato” e restitui-

sce una pagina HTML pura. La potenza di questo genere di linguaggi è, di fatto, l’alta

portabilità e l’immediatezza tra quello che scriviamo e quello che viene presentato all’e-

secuzione del programma, ma rimangono dei problemi come la ricerca di errori nel codice

sorgente o il carico di lavoro maggiore per il processore (che ogni volta deve elaborare la pagina).

Un linguaggio che è a metà strada tra queste metodologie è Java che è sia compilato

che interpretato; il codice sorgente viene compilato in un formato intermedio (chiamato

bytecode), il quale a sua volta viene interpretato dalla Java Virtual Machine (JVM), che ha il

compito di interpretare “al volo” le istruzioni bytecode in istruzioni per il processore; la JVM

viene sviluppata per ogni Sistema Operativo e permette di astrarre la macchina virtuale creata

dal SO ad un livello di standardizzazione superiore (data di fatto dalla creazione della virtual

machine sopra un’altra virtual machine) che rende, in pratica, JAVA altamente portabile.

Questa metodologia implica la possibilità di controllare eventuali errori del codice sorgente

(grazie alla compilazione), di creare programmi relativamente leggeri (il bytecode è un formato

che crea file di dimensioni ragionevoli), ma ha la pecca di avere delle prestazioni non proprio

soddisfacenti, questo perché il codice viene interpretato dalla JVM che a sua volta deve delegare

l’esecuzione vera e propria al Sistema Operativo.

1.1.1 Gestione della memoria nella JVM

La memoria usata dalla JVM è concettualmente divisa in tre parti:

• Ambiente delle classi: area di memoria in cui vengono caricate (allocate) tutte le classi che

costituiscono il programma.

Nell’ambiente delle classi quindi:

– vengono memorizzati il codice dei metodi e le variabili statiche di tutte le classi del pro-

gramma

– sono le parti condivise dai vari oggetti della classe

– le variabili statiche sono utilizzabili anche in assenza di oggetti

• Stack: area di memoria in cui vengono caricati (allocati) i record di attivazione dei metodi, e

quindi tutte le variabili locali.

Nello stack quindi:

– vengono memorizzate le variabili locali dei metodi in esecuzione

– per le variabili di tipi primitivi viene memorizzato il valore (esempio: somma)

– per le variabili di tipo classe viene memorizzato un riferimento (indirizzo di memoria di un

oggetto)

• Heap: area di memoria in cui vengono caricati (allocati) tutti i vari oggetti creati nel programma,

man mano che vengono creati.

Nell’heap quindi: 4

– per ogni oggetto creato vengono memorizzate le variabili d’istanza (ossia, le variabili non

statiche)

– ogni oggetto nell’heap contiene anche il nome della classe di appartenenza

1.1.2 Riferimenti e valori

Rinfreschiamo la memoria (la nostra, non quella della JVM).

Quando un parametro viene passato per riferimento, il chiamante e il chiamante usano la stessa

variabile per il parametro. Se la chiamata modifica la variabile del parametro, l’effetto è visibile alla

variabile del chiamante (tipo puntatore in C).

Quando un parametro viene passato per valore, il chiamante e il chiamante hanno due variabili indi-

pendenti con lo stesso valore. Se la chiamata modifica la variabile del parametro, l’effetto non è visibile

al chiamante (copia).

In Java le variabili associate a tipi primitivi sono passate a un metodo come valore.

Cioè viene fatta una copia e questa e’ passata al metodo. Modifiche al valore passato non influenzano

la variabile nel codice che richiama il metodo. Quindi ad esempio se si assegna un variabile int x =

e poi si fa succede che sia che hanno valore 15. Se poi si fa il valore di

15 int y = x, y x y = 40,

cambia, ma quello di rimane 15.

y x

Una variabile di un tipo classe contiene invece un riferimento a un oggetto.

Quindi ad esempio se si crea una variabile di tipo Rettangolo (che ha come attributi base e altezza)

e se ne crea un oggetto: la creazione dell’og-

Rettangolo primo = new Rettangolo(10,30),

getto primo alloca un nuovo oggetto e assegna un riferimento alla variabile. Se poi si fa Rettangolo

tale assegnamento fa si che e facciano riferimento alla stes-

secondo = primo, secondo primo

sa cella di memoria dove è contenuto l’oggetto, infatti se poi si fa anche

secondo.base = 186,

sarà 186.

primo.base

Lo stesso discorso vale anche quando si passa un oggetto a un metodo come parametro.

Una conseguenza del fatto che le variabili di tipo classe contengono riferimenti, è che l’operatore di

confronto non si comporta (con gli oggetti) come uno si potrebbe aspettare, infatti se si prova a

==

fare oggetto1 == oggetto2 ad esempio in un if, questo è true solo se i due fanno riferimento allo stesso

oggetto, perciò si usa equals().

1.1.3 Memoria

In Java tutte le entità sono allocate dinamicamente (per esempio non esistono variabili globali).

Tuttavia, solo l’allocazione della memoria (creazione di oggetti) viene gestita esplicitamente,

La deallocazione è gestita dalla macchina virtuale (garbage collection)

Garbage collection Per Garbage Collection si intende una modalità automatica di gestione della

memoria, mediante la quale un sistema operativo, o un compilatore e un modulo di run-time liberano

porzioni di memoria non più utilizzate dalle applicazioni. In altre parole, il garbage collector annoterà

le aree di memoria non più referenziate, cioè allocate da un processo attivo, e le libererà automatica-

mente.

Questo meccanismo ha provocato un notevole cambio nello stile di programmazione dei linguaggi che

lo implementano. Infatti non è più necessario richiedere esplicitamente la liberazione della memoria

utilizzata da un oggetto, ovvero terminare tale oggetto in modo deterministico, ma si lascia che il

sistema esegua questa operazione automaticamente, nel momento in cui lo riterrà più opportuno al

fine di migliorare le prestazioni complessive.

Il Mark and Sweep è un algoritmo di garbage collection che prevede l’interruzione dell’esecuzione,

in una prima fase (mark ) si marcano tutti gli oggetti accessibili. In una seconda fase (sweep) si rimuo-

vono gli oggetti non marcati (e si rimuove il marcatore dagli altri).

Si usa quando gli oggetti sono molti e globalmente accessibili.

Il Reference Counting è un algoritmo di garbage collection che non prevede l’interruzione dell’ese-

cuzione. Funzionamento: 5

Si incrementa/decrementa un contatore quando un oggetto viene referenziato/dereferenziato.

Vengono rimossi gli oggetti con contatore a zero.

Viene usato quando gli oggetti sono pochi e/o non raggiungibili globalmente (per esempio sistema

distribuito, ossia un insieme di processori indipendenti interconnessi da una rete di comunicazione).

1.2 I tre paradigmi

1.2.1 Incapsulamento

E’ il meccanismo che collega il codice e i dati che manipola, mantenendoli al sicuro da interferenze

esterne e da utilizzi impropri. Si può pensare all’incapsulamento come un rivestimento protettivo che

impedisce l’accesso arbitrario a codice e dati da parte di altro codice definito fuori dal rivestimento.

L’accesso al codice e ai dati all’interno del rivestimento è strettamente controllato mediante un’inter-

faccia ben definita.

Si può fare un paragone con il mondo reale pensando alla trasmissione automatica (cambio automati-

co) di una automobile. Questa incapsula centinaia di informazioni su motore, accelerazione, pendenza

della strada ecc... ma l’utente ha solo un metodo per influenzare tale incapsulamento complesso: la

leva del cambio.

Il Java la base dell’incapsulamento è la classe. All’interno di questa si può contrassegnare ciascun

metodo o variabile come privato o pubblico. L’interfaccia pubblica di una classe rappresenta tutto ciò

che gli utenti esterni hanno necessità di sapere, o possono sapere. Codice o dati non membri della

classe non possono accedere a metodi o variabili private di quella classe, possono farlo mediante metodi

pubblici della classe, evitando cosı̀ azioni scorrette.

1.2.2 Ereditarietà

L’ereditarietà è il processo con cui un oggetto acquisisce le proprietà di un altro oggetto. E’ impor-

tante, perché supporta il concetto di classificazione gerarchica.

Nel mondo reale ad esempio, un Labrador fa parte della classificazione cane, che a sua volta fa parte

della classe mammiferi, che si trova sotto la classe animali, di dimensioni maggiori. Senza l’utiliz-

zo delle gerarchie, ogni oggetto dovrebbe definire esplicitamente tutte le proprie caratteristiche, ma

mediante l’ereditarietà un oggetto deve definire solo le qualità che lo rendono unico all’interno della

relativa classe e può ereditare gli attributi generali dal suo genitore. Se si desiderasse descrivere gli

animali in modo astratto, si direbbe che dispongono di alcuni attributi quali dimensioni, intelligenza

e tipo di sistema scheletrico.

Se si desidera descrivere una classe di animali più specifica, per esempio i mammiferi, avrebbero at-

tributi più specifici, quali il tipo di denti e di ghiandole mammarie. Ciò è noto come

Anteprima
Vedrai una selezione di 7 pagine su 30
Appunti di Programmazione ad oggetti Pag. 1 Appunti di Programmazione ad oggetti Pag. 2
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Appunti di Programmazione ad oggetti Pag. 6
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Appunti di Programmazione ad oggetti Pag. 11
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Appunti di Programmazione ad oggetti Pag. 16
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Appunti di Programmazione ad oggetti Pag. 21
Anteprima di 7 pagg. su 30.
Scarica il documento per vederlo tutto.
Appunti di Programmazione ad oggetti Pag. 26
1 su 30
D/illustrazione/soddisfatti o rimborsati
Acquista con carta o PayPal
Scarica i documenti tutte le volte che vuoi
Dettagli
SSD
Scienze matematiche e informatiche INF/01 Informatica

I contenuti di questa pagina costituiscono rielaborazioni personali del Publisher dennisrapa di informazioni apprese con la frequenza delle lezioni di Programmazione ad oggetti e studio autonomo di eventuali libri di riferimento in preparazione dell'esame finale o della tesi. Non devono intendersi come materiale ufficiale dell'università Università Politecnica delle Marche - Ancona o del prof Frontoni Emanuele.
Appunti correlati Invia appunti e guadagna

Domande e risposte

Hai bisogno di aiuto?
Chiedi alla community