vuoi
o PayPal
tutte le volte che vuoi
Interfacce
Un’interfaccia è una collezione di metodi headers (senza la loro definizione). Un’interfaccia può anche dichiarare costanti. Appaiono simili alle classi
astratte ma hanno significative differenze:
1. Un’interfaccia non può avere metodi con lʼimplementazione.
2. Una classe può implementare molte interfacce ma può essere derivata da una sola superclasse.
3. Le interfacce non fanno parte della gerarchia delle classi. Esempio: una classe derivata non eredita da una superclasse le interfacce
implementate.
modificatori di un’interfaccia:
Annotazioni: discorso analogo per i casi precedenti.
Public: se è omesso la visibilità è package.
abstract (omesso): non vi è bisogno di dichiararlo poiché è automatico essendo un’interfaccia.
strictfp: discorso analogo per i casi precedenti.
Gerarchia delle interfacce
Le interfacce hanno una propria gerarchia, quindi anche su di esse funzionano le caratteristiche dell’ereditarietà. Su java le interfacce hanno la
possibilità di utilizzare l’ereditarietà multipla, ovvero un’interfaccia può avere due interfacce madri.
interfacce standard( package di Default)
Clonable
Comparable
Runnable
Serializable
Slide 14
Definizione di polimorfismo
Un metodo si dice polimorfo quando è in grado di adattare il suo comportamento allo specifico oggetto su cui deve operare. In altre parole, il
polimorfismo consente di invocare lo stesso metodo su oggetti di tipi diversi e ottenere comportamenti specifici per ciascuno di essi.
Binding statico: avviene durante la fase di compilazione. In questo caso, il compilatore è in grado di determinare esattamente quale metodo
o variabile utilizzare in base al tipo dell’oggetto. Viene utilizzato principalmente per metodi e variabili statici, oltre che per metodi privati e
finali. avviene durante l’esecuzione del programma (runtime). In questo
Binding dinamico: o anche chiamato late binding
caso, il metodo viene associato all'oggetto al momento dell'esecuzione, quindi può variare in base al tipo
effettivo dell’oggetto. Si applica ai metodi istanza non finali, che possono essere sovrascritti dalle sottoclassi.
definizione del casting nel polimorfismo
Upcasting: Conversione di un oggetto da un tipo derivato (sottoclasse) a un tipo base (superclasse). Di solito non richiede un cast esplicito,
poiché è implicito.
Downcasting: Conversione di un oggetto dal tipo base al tipo derivato. Questo richiede un cast esplicito e può lanciare un’eccezione
(ClassCastException) se l'oggetto non è realmente del tipo della sottoclasse
Slide 16
Definizione di un’eccezione
Spesso vi sono istruzioni “critiche”, che in certi casi possono produrre errori.
Java introduce il concetto di eccezione, anziché tentare di prevedere le situazioni di errore, si tenta di
eseguire l’operazione in un blocco controllato. Se si produce un errore, l’operazione lancia un’eccezione (sollevamento di una eccezione).
Cos’è un’eccezione
Un’eccezione può essere un dato in input errato, un file aperto o chiuso in maniera errata. Esistono molti tipi di eccezzioni predefinite disponibili su
java. Una eccezione è un oggetto, istanza di Throwable o di una sua sottoclasse: Exception o Error.
Un Error indica problemi relativi al funzionamento della macchina virtuale Java e va solitamente considerato irrecuperabile: perciò non è da
catturare, né da gestire
Una Exception indica invece situazioni recuperabili, almeno in linea di principio: va quindi catturata e gestita
Default Exception Handler
è il gestore di eccezioni predefinito fornito dalla Java Virtual Machine (JVM). Entra in gioco quando un’eccezione non viene gestita esplicitamente
try-catch
nel codice (ovvero, quando non ci sono blocchi per catturarla).
Quando si verifica un errore: JVM costruisce una nuova eccezione
Lancia (throws) lʼeccezione
Se non è stato fornito il gestore dellʼeccezione ad-hoc viene utilizzato il gestore delle eccezioni di default
Mostra una stringa che descrive lʼeccezione
Traccia il punto del programma in cui lʼeccezione si è verificata
Termina il programma
Una eccezione non controllata può propagarsi di blocco in blocco: se raggiunge il main senza essere stata catturata, il programma abortisce.
Creazione di nuove eccezioni
Lo sviluppatore se lo ritiene opportuno può definire nuove eccezioni, creando una classe che estenderà la classe Exception e definendo all’interno i
comportamenti di quella nuova eccezione. Poiché un’eccezione è un’oggetto, può contenere dati e metodi.
Blocchi try-catch
Per controllare un’eccezione viene utilizzato il costrutto try-catch
Try: al suo interno vengono inserite le istruzioni che si vogliono gestire e che potrebbero sollevare un’eccezione.
Catch: al suo interno vengono inserite le exception da chiamare qual’ora il blocco try solleva un eccezione.
Finally: al suo interno vengono inserite una serie di istruzioni da eseguire alla fine del sollevamento di un’eccezione(esempio chiusura dei file).
tecniche di Exception Handling: ʼ
Terminare il programma: Stampa un messaggio per notificare l errore prima di terminare
ʼ
Fix error e continue: Stampa un messaggio per notificare l errore fino a quando non viene inserito un valore valido. Richiede l’input
ripetutamente. ʼ ʼ
Log error e continue: Stampa un messaggio per notificare l errore in un file e continua con l esecuzione del programma.
Slide 17
definizione di flusso
sono una sequenza ordinata di dati usati per leggere o scrivere dati tra un programma Java e una sorgente o
destinazione (come un file, la console o una rete). I flussi consentono la gestione dell'input e dell'output in modo
efficiente, permettendo di lavorare con dati come byte o caratteri.
Flussi di Byte: Lavorano a livello di byte e sono adatti per leggere e scrivere file binari (come immagini o file
audio).
Flussi di Caratteri: Lavorano a livello di caratteri e sono più adatti per la lettura e la scrittura di file di testo.
Le 4 classi base astratte del package java.io
1. Flussi di Byte: Questi flussi trattano i dati come byte grezzi e sono utili per file binari.
InputStream: Classe base per leggere byte.
FileInputStream: Legge byte da un file.
ByteArrayInputStream: Legge byte da un array di byte in memoria.
OutputStream: Classe base per scrivere byte.
FileOutputStream: Scrive byte su un file.
ByteArrayOutputStream: Scrive byte in un array di byte in memoria.
Sia InputStream che OutputStream sono delle classi astratte:
Definiscono il concetto generale rispettivamente di “flusso di input" e “flusso di output” operante
sui byte
Dichiara i metodi che permettono rispettivamente di leggere e di scrivere dei byte a partire da
una specifica sorgente
I metodi dovranno essere realmente definiti dalle classi derivate, in modo specifico alla specifica
sorgente dati.
Il metodo costruttore per entrambi apre lo stream
2. Flussi di Caratteri: Questi flussi trattano i dati come caratteri e sono più utili per lavorare con file di testo.
Reader: Classe base per leggere caratteri.
FileReader: Legge caratteri da un file.
BufferedReader: Legge caratteri da una sorgente con buffering, migliorando le prestazioni.
Writer: Classe base per scrivere caratteri.
FileWriter: Scrive caratteri su un file.
BufferedWriter: Scrive caratteri su una destinazione con buffering, migliorando le prestazioni.
Conversione di flussi
Tipi di Conversione dei Flussi
1. Conversione da Flussi di Byte a Flussi di Caratteri: Questa conversione è necessaria quando si leggono
dati da un file binario e si desidera trattarli come testo (caratteri).
2. Conversione da Flussi di Caratteri a Flussi di Byte: Utilizzata quando si scrivono dati di testo in un file
binario o in un formato non testuale.
Classi Utilizzate per la Conversione dei Flussi
1. InputStreamReader: Converte un flusso di byte in un flusso di caratteri.
2. OutputStreamWriter: Converte un flusso di caratteri in un flusso di byte.
Flussi filter: La funzionalità di filtering consente di selezionare elementi da un flusso basato su criteri specifici.
Questo è particolarmente utile quando si lavora con collezioni di dati e si desidera estrarre solo gli elementi che
soddisfano determinate condizioni.
Flussi buffered: in Java si riferiscono all'uso di buffer per migliorare le prestazioni durante le operazioni di input e
output. Utilizzando un buffer, i dati vengono letti o scritti in blocchi anziché singolarmente, riducendo il numero di
operazioni di I/O e aumentando l'efficienza complessiva.
Flussi piped: in Java sono una particolare implementazione di flussi che consente a due thread di comunicare tra loro
in modo efficiente utilizzando i flussi di input e output. Questa comunicazione avviene attraverso un "tubo" (pipe), dove
un thread scrive dati nel flusso di output e un altro thread legge quei dati dal flusso di input. I flussi piped sono
particolarmente utili per la comunicazione inter-thread, in cui è necessario passare dati tra diverse parti di
un'applicazione.
Flussi buffered: I flussi bufferizzati in Java migliorano l'efficienza delle operazioni di input/output (I/O) riducendo il
numero di accessi diretti al file system o alla sorgente di dati. L’uso di buffer permette di raggruppare i dati in blocchi,
così da leggere e scrivere una quantità maggiore di dati in una singola operazione, riducendo il tempo di attesa per
ogni accesso.
1. BufferedInputStream: incapsula uno InputStream per bufferizzare le operazioni di lettura. I dati vengono letti
in blocchi e immagazzinati in memoria, da cui poi vengono letti a piccole dosi quando richiesto, evitando
letture frequenti dal dispositivo di origine.
2. BufferedOutputStream: incapsula uno OutputStream e accumula i dati in un buffer prima di scriverli in blocco
sulla destinazione, ottimizzando il numero di scritture. I dati nel buffer vengono svuotati (flush) quando il
buffer è pieno o quando viene invocato il metodo flush().
Flussi print: I flussi di stampa (o flussi Print) in Java facilitano l’output di dati testuali e di valori primitivi in maniera
semplice e leggibile. Questi flussi permettono di scrivere direttamente oggetti, numeri, caratteri e stringhe in formati
standard tramite i metodi print() e println().
Sincronizzazione e Concorrenza
Nell’uso di flussi multipli da più thread, java.io implementa meccanismi di sincronizzazione per assicurare l’atomicità
delle operazioni. Nei flussi di byte, il flusso stesso è bloccato per evitare che due thread simultanei interferiscano con le
operazioni d