Introduzione a Java
Java è un linguaggio di programmazione ad alto livello, orientato agli oggetti (OOP), creato per essere indipendente dall’hardware di esecuzione attraverso la compilazione in un codice binario intermedio (bytecode) prima e tramite l’interpretazione da parte di una Macchina Virtuale chiamata JVM (Java Virtual Machine) poi: questa particolarità causa una minore velocità rispetto ai linguaggi direttamente compilati come ad esempio C++, ma una maggiore portabilità.
Nel 1992 nasce il linguaggio Oak della Sun Microsystems (acquistato da Oracle nel 2010) a opera di un gruppo di sviluppatori con a capo James Gosling. Oak prese successivamente il nome Java (Java 1 è del 1995); la sintassi di base di questo linguaggio è stata mantenuta simile al C in modo da facilitarne l’adozione da parte degli sviluppatori di quest’ultimo. Per le caratteristiche orientate agli oggetti ci si è ispirati a C++ e Objective C.
Java dovrebbe risultare più semplice rispetto a C++ dato che manca dei costrutti legati alla gestione dei puntatori e della memoria, per quest’ultima si basa infatti su un sistema detto garbage collection in cui la memoria viene automaticamente assegnata e rilasciata in base alle esigenze del programma. I programmi non sono compilati in codice macchina ma in un bytecode che non è eseguito direttamente dall’hardware ma che va interpretato da un altro programma, la macchina virtuale. Ciò fa sì che lo stesso codice possa essere eseguito su più piattaforme trasferendo il bytecode (non il sorgente) purché si abbia una JVM: da qui nasce l’acronimo WORA, write once, run everywhere. Scrivi una volta, esegui ovunque.
Java e JavaScript non hanno invece quasi nessun parallelismo: il nome è simile per motivi di marketing.
Schematizzazione della compilazione ed esecuzione di un programma:
1 Editor
es. Blocco note,
Eclipse
2 Codice sorgente
.java
3 Comando javac
Compilazione
4 Bytecode
.class
5 Comando java
Esecuzione
Tecniche di programmazione
Esistono i metodi di programmazione:
- di tipo procedurale (Procedural Programming) - Nei programmi procedurali (es. Cobol, Fortran, Basic) le istruzioni, che vengono eseguite sequenzialmente una dopo l'altra, sono organizzate in blocchi (subroutine o function) studiati per un preciso scopo, accessibili a cascata o attraverso il comando goto da più punti del codice. Il codice è eseguito dall'inizio alla fine (top-down) ed è semplice da seguire
- di tipo strutturata (Structured Programming) - Concorre alla nascita della programmazione strutturata la critica al goto, che rappresentava, negli anni Sessanta, lo strumento principe usato in programmazione, ma deleterio per leggibilità e modificabilità del software (il cosiddetto problema dello spaghetti code) e che quindi non dovrebbe essere usato. Mantiene un approccio top-down ma l'esecuzione delle istruzioni non è obbligatoriamente in ordine sequenziale bensì influenzata da cicli e condizioni basate sul valore dei dati (es. C, Pascal, Algol)
- orientata agli oggetti (Objected Oriented Programming - OOP) - Il modello OOP (es. Java, C#, C++) necessita di maggiore codice perché bisogna prima instanziare un oggetto (una sorta di contenitore detto classe), ma ha un’implementazione centralizzata su quell’oggetto e tutti gli oggetti possono comunicare tra loro, ciò consente una potenzialità maggiore. L’OOP rende inoltre il codice facile da manutenere ed estendere, ottima caratteristica nei progetti di grandi dimensioni. Diversamente dai linguaggi già descritti, gli OOP hanno un approccio di progettazione bottom-up, ovvero la prima cosa da fare è la progettazione degli oggetti
Programma compilato e interpretato
Un programma si sviluppa scrivendo codice sorgente in un certo linguaggio.
Linguaggi come FORTRAN, COBOL , C-based (C, C++, C#) .NET, Objective-C, Visual Basic, ecc. sono linguaggi compilati e seguono questi passi:
- si scrive il codice sorgente in un editor o in un ambiente di sviluppo IDE
- il codice viene controllato per verificare che non ci siano errori
- il codice viene compilato da un programma detto compilatore, ovvero ogni istruzione viene trasformata nel corrispondente codice in linguaggio macchina che può essere, così, eseguito dal processore
I linguaggi compilati hanno ottime prestazioni.
Nei linguaggi interpretati, ad esempio PHP o Perl, il codice sorgente viene invece interpretato al volo da un programma chiamato interprete che traduce istantaneamente il codice sorgente in linguaggio macchina; ad esempio quando il codice PHP viene elaborato, restituisce una pagina HTML pura.
I linguaggi interpretati hanno alta portabilità, ma problemi relativi al carico di lavoro maggiore per il processore (che ogni volta deve elaborare la pagina) e nella ricerca di errori nel codice sorgente.
Java è una via di mezzo, è sia compilato che interpretato: il codice sorgente viene compilato in un formato intermedio (chiamato bytecode) che fornisce un file con estensione .class, il quale viene interpretato dalla Java Virtual Machine (JVM), che ha il compito di interpretare al volo le istruzioni bytecode in istruzioni per il processore ed eseguire il programma. È uno dei punti di forza del Java, che lo ha reso portabile verso ogni piattaforma. Questa metodologia implica inoltre 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 prestazioni non proprio ottime.
Java Esempio.java Compilazione Esempio.class Interpretazione Java Virtual Machine Esecuzione Macchina reale |
C++ Esempio.cpp Compilazione Esempio.exe Esecuzione - - Macchina reale |
Installare il JDK
Java ha alcune piattaforme principali tra le quali:
- Java 2 Standard Edition (J2SE): contiene il Java Developer Kit (JDK) per compilare i codici sorgenti Java, è la piattaforma che ci interessa
- Java 2 Enterprise Edition (J2EE): dedicata a soluzioni Client - Server
- Java 2 Micro Edition (J2ME): per i dispositivi portabili, come smartphone o palmari
Cliccate su www.oracle.com/java/technologies/javase-jdk14-downloads.html per scaricare JDK per Linux, MacOS o Windows. Alternativa OpenJDK. L’installazione è automatica e basta accettare i default.
Per verificare la corretta installazione eseguite la macchina virtuale, ad esempio aprendo il prompt dei comandi e scrivendo:
java -version
Primo programma in Java e IDE
È raro scrivere un programma totalmente a mano perché di solito ci si fa aiutare da un IDE (ad esempio, Eclipse), ma si potrebbe usare anche il Blocco Note. In tal caso bisognerebbe:
- scrivere il codice all’interno del Blocco note e salvare il file con estensione .java (facendo attenzione che il nome della classe corrisponda a quello del file se la classe è stata dichiarata pubblica con public class)
- compilare il file con il comando javac. Ad esempio se il file si trovasse nella directory C:\Users\Andrea\Desktop e si chiamasse Primo.java il comando sarebbe:
javac C:\Users\Andrea\Desktop/Primo.java
la cui esecuzione dovrebbe produrre, accanto al file .java, il file Primo.class (in bytecode)
ma in realtà darebbe un errore del tipo:
PrimoProgramma.java non è riconosciuto come comando interno o esterno, un programma eseguibile o un file batch
perché anche se il compilatore JDK è installato, la cartella del compilatore non è inclusa nell'ambiente di lavoro del sistema operativo (oltre al fatto che il file risiede sul percorso C:\Users\Andrea\Desktop). Vanno allora impostate le variabili d’ambiente.
Il compilatore javac si trova nella cartella bin di JDK, ad esempio il mio è nel path
C:\Program Files\Java\jdk-14.0.2\bin
Per usare il compilatore devo allora includere questo percorso nelle variabili di ambiente del sistema. Vediamo come su Windows:
- Pannello di controllo icona Sistema Impostazioni di sistema avanzate Variabili d’ambiente
Nella parte inferiore, quella delle variabili di sistema, seleziono la voce PATH e clicco Modifica… sempre posto in basso. - Poi clicco su Nuovo in alto a destra e aggiungo la directory che, come detto, nel mio caso è C:\Program Files\Java\jdk-14.0.2\bin. Infine clicco Ok (Ora il comando javac funzionerà da qualsiasi altra directory del PC perché si trova nelle variabili di sistema)
- Chiedere alla macchina virtuale JVM di eseguire il programma con il comando java Primo, dove Primo è il nome della classe e non del file .class
Il tutto risulterebbe macchinoso in modo evidente. Che fare per alleggerire il lavoro?
La soluzione è utilizzare un IDE (Integrated Development Environment) di sviluppo (ad esempio NetBeans, Eclipse, IntelliJ) che velocizzano il lavoro; esso consente ad esempio la colorazione del codice, il suo auto completamento e le minore laboriosità. Per l’eventuale generazione dei file jar e la gestione complessiva dei progetti può aiutare un’applicazione come Maven.
Non esiste un IDE migliore perché sono software estendibili con centinaia di plugin. Qui useremo Eclipse, che è utile anche per altri linguaggi. Per installarlo basta scaricare l’archivio ed eseguirlo per esempio dal seguente URL:
https://eclipse.bluemix.netpackages2020-06?INSTALLER-WIN64.
In tal caso scegliete:
Eclipse IDE for Java Developers
The essential tools for any Java developer, including a Java IDE, a Git client, XML Editor, Maven and Gradle integration.
Lasciate le selezioni di default e completate l’installazione. Quando ricevete la schermata che notifica il successo dell’installazione, lanciate Eclipse.
Una volta avviato, viene chiesto di selezionare una directory di riferimento (workspace) dove Eclipse organizza i progetti, anche qui potete lasciare il default.
Per creare un progetto:
- cliccare File New Java Project. Si apre una finestra per inserire il Project name (Primo), cliccate Next e poi Finish
- Con il tasto destro cliccate su Primo in alto a sinistra e scegliete New Class; nella finestra che compare date il nome alla classe (Prova) e selezionate la casella di controllo public static void main(String[] args), poi cliccate Finish
Comparirà un listato di codice nel quale, dopo la riga
public static void main(String[] args) {
/ TODO Auto-generated method stub
Dovete aggiungere
System.out.println("Ciao mondo");
Fate molta attenzione a maiuscole e minuscole, se ad esempio scrivete Out o PrintIn non funziona.
La riga
// TODO Auto-generated method stub
è un commento e può essere eliminata.
Con il pulsante circolare verde che contiene una freccia bianca posto in alto a sinistra (o dalla voce di menu Run in alto) eseguite il programma e visualizzate l’output (se avete fatto errori verrà segnalato) senza uscire dall’IDE. Verrà anche creato il file .class.
Come vedete utilizzando un IDE non c’è bisogno di usare il prompt dei comandi.
Il file completo è dunque:
public class Prova {
public static void main(String[] args) {
System.out.println("Ciao mondo");
}
}
Classi e oggetti
I programmi scritti con linguaggi di programmazione orientati agli oggetti come Java, sono formati da classi che rappresentano gli oggetti del mondo reale. Questo metodo OOP è dunque basato su due concetti fondamentali:
- Classe: contenitore di oggetti con medesime peculiarità. All’interno della classe i metodi sono funzioni che espletano compiti
- Oggetto (o Istanza): realizzazione concreta di una classe. Per definire un oggetto vanno individuate:
- le sue caratteristiche (attributi) attraverso variabili che rappresentano l’oggetto
- le azioni che può eseguire (metodi)
Per convenzione i nomi:
- delle classi hanno iniziale maiuscola, es. Conto; se il nome è di più parole ContoCorrente (CamelCase o AltoBasso) anche se in realtà pippo, PIPPO, PippO1, pippo_, _pippo sono tutti validi
- dei metodi delle classi e degli attributi: hanno iniziale minuscola; se il nome è di più parole quelle successive hanno iniziale maiuscola es. versamentoEuroAssegno
Ad esempio per una classe AnimaleDomestico dovremmo decidere le azioni (metodi) dell’animale (dormire, mangiare, parlare, ecc.) e gli attributi (anni, altezza, peso, colore)
oppure
per una classe Videogioco ha metodi che dicono cosa possono fare i suoi oggetti (Iniziare il gioco, Terminare il gioco, Salvare il Punteggio, ecc.) e attributi che descrivono gli oggetti (Prezzo, Colore dello Schermo, ecc.) che in Java si potrebbe scrivere con il seguente codice (che comunque non funzionerebbe perché mancante di alcuni elementi tra i quali il metodo main):
public class Videogioco {/Dichiaro una classe pubblica
string colore;
int prezzo;
void iniziareIlGioco () {
}
void terminareIlGioco () {
}
void salvareIlPunteggio(string nomeGiocatore, int punteggio) {
}
Da cui possiamo dedurre che:
- i Qualificatori (o modificatori) di visibilità stabiliscono la visibilità degli elementi cui sono applicati:
- Private: elemento visibile solo all’interno della classe che lo contiene
- Public: elemento accessibile anche fuori dalla classe
- Protected: elemento accessibile solo dalle classi derivate
- Default: si ha in caso nessun qualificatore precedente venga specificato e implica visibilità per tutte le classi all’interno dello stesso package (un package, ad esempio package primo.progetto; posto prima della dichiarazione di una classe, per esempio public class Videogioco { raggruppa le classi in modo che il codice sia più leggibile)
- una classe si dichiara con la parola chiave class
- il corpo della classe va tra parentesi graffe
- le linee terminano con punto e virgola
- il commento s’imposta con il doppio slash // o con /* e */
// Questo è un commento monolinea
/* Questo è un commento
multilinea
*/ - (un eventuale doppio asterisco all’inizio di un commento /** serve a generare documentazione dai commenti nel codice
Il programma scritto prima potrebbe ora risultare meno oscuro:
public class Prova {
public static void main(String[] args) {
System.out.println("Ciao mondo");
}
}
public class Prova {/dichiaro una classe pubblica Prova. la parola che segue class è il nome del file sorgente senza la estensione .java
public static void main(String[] args) {/metodo main il cui parametro String args[] salva nell’array args eventuali stringhe digitate dall’utente. Il metodo main dev’essere il primo da eseguire.
System.out.println("Ciao mondo");/ stampa a video un testo, il valore di una variabile o il risultato che ritorna un metodo, seguito da un ritorno a capo
Per eseguire più stampe è possibile mettere queste istruzioni una dopo l'altra
System.out.println("uno");
System.out.println("due");
System.out.println("tre");
Il listato precedente stampa Ciao mondo, ma non sfrutta il modello OOP. Per ottenere lo stesso risultato attraverso una codice orientato agli oggetti:
public class Msg {
private String toPrint;
public Msg(String print) {
this.toPrint = print;
}
public void print() {
System.out.println(this.toPrint);
}
public static void main(String args[]) {
Msg ciaoMondo = new Msg("Ciao Mondo");
ciaoMondo.print();
}
}
Senza addentrarci nel codice, perché dovrei utilizzare questa seconda sintassi OOP più lunga? In quanto è possibile cambiare totalmente il comportamento del programma con modifiche localizzate e perché il listato può resistere a esigenze impreviste di implementazione.
Se desideri approfondire Java (o C C++), anche con la programmazione orientata agli oggetti (OOP) e allenarti con esercizi (e soluzioni), ti consiglio...
Fondamenti di Java Teoria e pratica
Versioni cartacea e digitale aggiornate a Febbraio 2023 - 303 pagine
LINK TESTUALE versione digitale
LINK TESTUALE versione cartacea
Questo manuale fornisce le basi per diventare un programmatore Java. Lo fa senza appesantire troppo la teoria, che comunque tratterà dei costrutti fondamentali di questo linguaggio, ma attraverso molti codici commentati in italiano. Verrà introdotta anche la programmazione a oggetti (OOP Object Oriented Programming). Un testo ricco di contenuti ed esempi, utile ai neofiti della programmazione. Il manuale contiene il link per scaricare tutti i codici Java, e relativi commenti, degli esempi proposti.