Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
Scarica il documento per vederlo tutto.
vuoi
o PayPal
tutte le volte che vuoi
Utilizzo delle caratteristiche statiche
Per invocare tali caratteristiche statiche dall'esterno della classe che le contiene, dobbiamo utilizzare il nome della classe ed accedere al metodo o all'attributo utilizzando il punto.
Ereditarietà delle caratteristiche
Una classe può essere derivata da un'altra classe estendendone gli attributi e i metodi. In Java, si utilizza soltanto l'ereditarietà, quindi si può effettuare l'estensione da una sola classe.
La sintassi per effettuare tale estensione sarà: <nome_classe> extends <nome_classe>
N.B: Se omettiamo la keyword "extends", allora la classe viene derivata dalla classe predefinita "Object".
La classe derivata possiederà tutte le caratteristiche della classe padre, più altre caratteristiche aggiuntive della classe estesa.
Gli attributi ed i metodi dichiarati con visibilità "protected" sono accessibili anche dalle classi derivate (oltre che dalle altre classi dello stesso package).
classi che private appartengono allo stesso package). Al contrario, gli attributi dichiarati con visibilità non saranno visibili all’interno della classe derivata.
N.B: super all’interno della classe derivata è possibile richiamare il costruttore della classe padre attraverso la keyword che permette di fare riferimento ad un oggetto della classe padre. In questo modo è possibile inizializzare un oggetto della classe figlio, con attributi della classe padre. Ad esempio:
ES: Polimorfismo polimorfismo ridefinire Il permette di (override) un metodo in una classe derivata. I metodi Java sono tutti implicitamente polimorfi, quando vengono ridefiniti in una classe derivata (perciò non è necessario specificare l’azione di ridefinizione del metodo). @Override. È possibile specificare esplicitamente l’operazione di ridefinizione aggiungendo l’annotazione Rendendo esplicita l’intenzione di ridefinire un metodo, allora il compilatore
controlla se esiste il metodo nella classe padre e se è compatibile con quello della classe padre (ovvero se sono stati utilizzati gli stessi tipi e gli stessi parametri). In caso contrario, si ha un @Override
errore (senza l'annotazione ci saremmo accorti dell'errore solamente durante l'esecuzione).
ES: Classi astratte
Le classi astratte sono classi che non possono avere delle istanze dirette, perciò vengono utilizzate esclusivamente per derivare altre classi. Per definire una classe astratta, basta aggiungere la keyword abstract
davanti al nome della classe.
metodi astratti
Oltre alle classi astratte, possiamo definire dei metodi astratti, ovvero metodi senza implementazione che verranno implementati nelle classi derivate. Anche i metodi astratti vengono definiti con la keyword abstract
.
ES: Interfacce multipla
Come abbiamo visto, Java non permette l'ereditarietà multipla per problemi dovuti alla gestione degli attributi nell'ereditarietà a diamante. Per risolvere questo problema, Java permette l'implementazione di più interfacce.
Possiamo ovviare a questo problema definendo delle interfacce. Le interfacce sono delle classi che definiscono solo funzionalità (cioè metodi o attributi statici), ovvero non hanno attributi. Le interfacce danno la possibilità di definire l'insieme delle funzionalità che devono essere implementate per poter interagire con un insieme di classi.
Come abbiamo detto, possiamo avere metodi e attributi astratti pubblici. I metodi sono implicitamente pubblici.
Inoltre, un'interfaccia può essere derivata da altre interfacce. La caratteristica di queste interfacce è che una può essere derivata da più interfacce.
Sintassi per definire un'interfaccia:
interface [public] <Nome> [extends <Nome> [, <Nome>,…,<Nome>]] {
<metodi astratti pubblici>
<attributi statici>
<metodi statici>
}
Sintassi per definire una classe che deriva un'interfaccia:
class [public] <Nome> [extends <Nome>] [implements <Nome> [, <Nome>,…,<Nome>]] {
<attributi>
<metodi>
}
<Nome>][implements <Nome>[, <Nome>,…,<Nome>]]{…}
Una classe che implementa una o più interfacce deve definire tutti i metodi astratti delle interfacce (e di tutte le interfacce da cui eventualmente derivano).
ES: Cast cast
L’operatore permette di trasformare un’istanza di un tipo in un altro tipo meno preciso (ad esempio, si vuole assegnare una variabile long (a 64 bit) ad una variabile int (a 32 bit), perciò non si può fare un’assegnazione diretta, ma dobbiamo esplicitare con il cast che si vuole perdere dell’informazione dovuta alla trasformazione).
cast
Il si realizza mettendo tra parentesi tonde il tipo in cui si vuole trasformare l’istanza.
ES: long l = 10; int a = (int) l;
Perciò, il cast è necessario quando si vuole effettuare trasformazioni da int a byte, da int a short, da double a float, ecc…
cast reference reference
Tale operatore di può essere utilizzato per trasformare
una da un tipo ad un altro. Una ad una classe padre può essere trasformata in una ad una classe figlia tramite il cast. Quindi essere trasformata in una ad una classe figlia tramite il cast. ES: Persona p = new Studente();
...Studente s = (Studente) p;
Perciò, se punta effettivamente ad una istanza che è oppure ad una sua derivata, allora il cast va a buon fine. Se, però, ciò non si verifica, allora viene generata un'eccezione di tipo ClassCastException.
Il cast di una reference è necessario quando si vuole utilizzare un metodo o un attributo della classe derivata (Studente). E' possibile anche controllare se una reference punta ad un'istanza di una classe (oppure ad una sua derivata) tramite l'operatore instanceof. ES: Studente s = null;
...if (p instanceof Studente) s = (Studente) p;
Final
Il modificatore final
viene utilizzato per indicare che una variabile, un...
Un attributo o un metodo non sono più modificabili. Sono definiti come costanti. Perciò, tramite il modificatore final
possiamo dichiarare dei metodi, attributi o variabili come costanti.
Ad esempio:
// A è una costante intera (vale 1000 e non può più essere modificata)
final int A = 1000;
final float PI; // da questo punto in poi, PI non è più modificabile
PI = 3.14;
N.B: Una costante è definita come final
, static
e public
.
Un attributo rappresenta una caratteristica di un oggetto e viene dichiarato come final
.
N.B: Un metodo definito come final
indica che non può essere ridefinito in una classe figlia (ovvero, non possiamo effettuare l'override dei metodi dichiarati come final
nella classe padre).
N.B: Si può anche definire una classe come final
. Ciò indica che da tale classe non si può derivare altre classi.
Il package serve a raggruppare delle classi che sono semanticamente collegate. Ciò viene fatto per gestire la complessità di un'applicazione, quando il numero delle classi è molto elevato.
elevato.package package: I sono utilizzati anche nelle API di Java per organizzare la grande quantità di classi presenti. Vediamo alcuni di questi:
- java.io: fornisce l’input e l’output del sistema (contiene tutte le classi che forniscono I/O).
- java.lang: fornisce classi fondamentali per la progettazione del linguaggio di programmazione Java (ad esempio la classe Object).
- java.math: fornisce classi per l’esecuzione di calcoli aritmetici.
- java.net: fornisce classi per implementare delle applicazioni di rete.
- java.awt: fornisce classi per la creazione di interfacce utente e per disegnare e realizzare immagini.
Vediamo come possiamo utilizzare una classe package. Per utilizzare una classe interna ad un package possiamo usare due modi:
java.net.Address.getLocalHost()
- riferirci al nome completo (ad esempio, ip = import package).
- usare il costrutto import
all’inizio del file (per evitare di ripetere tutte le volte il nome completo).
package
. In questo modo possiamo riferirci direttamente alla classe contenuta all'interno del package
.
ES: import java.net.InetAddress;
...
InetAddress inetAddress = InetAddress.getLocalHost();
Si possono anche importare tutte le classi di un package
(invece di una sola classe specificata), specificando il nome del package
da importare seguito da un asterisco.
ES: import java.net.*;
...
InetAddress inetAddress = InetAddress.getLocalHost();
Si possono importare anche i package
e i subpackage
. Notiamo che i package
hanno un comportamento gerarchico. Perciò, se un package
contiene dei subpackage
, specificando con l'asterisco il nome del package
principale, non saranno importate anche le classi dei subpackage
, ma queste dovranno essere importate separatamente.
ES:
import java.awt.*;
import java.awt.font.*;
import java.awt.geom.*;
...
package.package;
È anche possibile definire un package
personalizzato. Per indicare il nome del package
spesso si utilizza il dominio DNS rovesciato per la ditta/istituzione (per cui stiamo realizzando l'applicazione) seguito dal nome del package
desiderato.
ES: package com.example.mypackage;
Dal nome dell'applicazione/libreria e quindi dal nome della sottoparte in cui è organizzata l'applicazione (ad esempio: it.unifi.myproject.db per le classi di gestione database).
Vediamo alcuni vincoli di cui dobbiamo tenere conto per la definizione di un package.
I file .java devono essere organizzati in una struttura di directory che seguono il nome del package. Ad esempio, la classe it.unifi.myproject.db.ImportData deve trovarsi nella cartella it/unifi/myproject/db/ImportData.java.
Inoltre, nelle prime righe del file della classe deve essere presente la dichiarazione di appartenenza al package. Ad esempio:
package it.unifi.myproject.db;
public class ImportData {
...
}
Quando il modificatore di visibilità (public/protected/private) di una classe, di un attributo o di un metodo viene omesso, allora la visibilità standard sarà package-private, ovvero visibile soltanto alle classi che fanno parte dello stesso package.
Streamsstream di input) di
output). Gli stream sono oggetti che permettono ad una applicazione di acquisire dati (stream di input) o di inviare dati (stream di output). Ad esempio, possiamo ottenere dati da tastiera (stream di input) e inviare dati in stampa sullo schermo (stream di output). Perciò, i dati vengono (pull) da ed (push) ad uno stream. Java fornisce un insieme di classi per la gestione di tali stream (java.io): Vediamo come si presenta la gerarchia degli stream (contenuti nel package java.io): - Stream di byte - Stream di caratteri Visualizziamo alcune classi della gerarchia: - FileInputStream: permette di leggere dati (byte) da un file in input ("file.bin"). Si può leggere un byte a