Esecuzione
Eseguire un oggetto
Un'unità di compilazione File.java si compila
usando il comando javac File.java.
Se non c'è alcun errore di compilazione, viene creato un file
A.class per ogni class A definita nell'unità
di compilazione.
Adesso si può eseguire un file di tipo A.class
usando il comando java A.
L'interprete Java prova a trovare dentro la class A
il metodo public static void main(String[] args)
Per esempio, se il file A.java contiene la seguente definizione:
class A {
public static void main(String[] args){
System.out.println("Hello Word");
}
}
Il comando javac A.java compila il file A.java e crea
un file A.class. Adesso facendo java A il
programma stampa Hello World e termina.
Il parametro è un array di stringhe che contiene i parametri
della chiamata.
Per esempio, se abbiamo:
class A {
public static void main(String[] args){
for(int i=0; i< args.length; i++) {
System.out.print(args[i]);
System.out.print(" ");
}
System.out.println("");
}
}
Adesso facendo java A Hello World, il
programma stampa Hello World e termina.
Esecuzione e package
Una variabile CLASSPATH determina dove sono depositati
i file Name.class. Una CLASSPATH è normalmente una
collezione di locazioni.
Supponiamo che questa classpath contenga solo la locazione root.
Se c'è un oggetto A definito nel package foo.bar,
il file A.class deve essere nella directory foo/bar.
Si chiama l'oggetto A facendo java foo.bar.A.
Inoltre se c'è un file A.java nella directory foo/bar, il compilatore javac si incarica di gestire le dipendenze.
Bytecode
Il languaggio Java vuole essere portatile.
Dunque il compilatore produce codice che è
independente da una architettura specifica. Tale codice
si chiama bytecode ed è contenuto nel file
A.class. Si può vedere il contenuto
di tale file usando il comando javap -c A.
Il motto di Java è:
"Compile once. Run everywhere"
JVM
Per potere eseguire programmi Java è dunque
sufficiente capire il bytecode. Il
bytecote corrisponde ad una macchina astratta chiamata
Java Virtual Machine o JVM.
In un certo senso, anche se Java utilizza un compilatore, il fatto che
ci sia una JVM vuole dire che il languaggio Java
è interpretato. Questo non è completamente
vero. Molte implementazioni della JVM sono dei
JIT (Just In Time Compiler) che fanno
compilazione dinamica.
Memoria
È Java che gestisce da sé l'uso della memoria. Per questo
in un progamma Java, si creano solo oggetti con new.
Il Garbage Collector è responsabile della individuazione
e dell'eliminazione di oggetti che non servono più.
Tale collector lavora da sé ma lo si può chiamare esplicitamente
usando il metodo System.gc().
Prima di eliminare un oggetto, il metodo finalize è
chiamato su tale oggetto. Cosí si possono chiudere
le risorse che non dipendono direttamente dalla memoria (file, connessione, etc..)
Sicurezza
Java è il primo languaggio per il quale nel design c'è stata
una vera preoccupazione dei problemi di sicurezza.
La ragione è che uno degli obiettivi di Java era quello di permettere
di comunicare codice attraverso la rete,
dunque di permettere a chiunque di eseguire in tutta sicurezza
sulla sua macchina codici scritti da altri.
Tipi
Avere tipi è importante perché assicura che gli oggetti
manipolati da Java sono manipolati correttamente.
Il programma può non terminare ma non farà
core dump.
Bytecode Verifier
Abbiamo visto che le JVM eseguono il bytecode. Ma prima di eseguire
questo bytecode bisogna verificare che tale codice è corretto.
Il bytecode generato dal compilatore Java è sicuro ma
quando si prende codice dalla rete, si prendono programmi in bytecode.
Forse questi programmi sono stati modificati per essere pericolosi
(virus,...). Dunque il bytecode verifier verifica che
il bytecode segue le regole di sicurezza del languaggio Java.
Class Loader
Il modello d'esecuzione di Java è quello di un'applicazione
che progressivamente incorpora di tanto in tanto nuovo codice.
Il class loader è l'oggetto che gestisce questa integrazione.
Dopo che una class A è stata caricata e validata dal bytecode
verifier, la class A resta associata con il suo class loader.
A sua volta quando un oggetto di tipo A richiederà il
caricamento di una class B, sarà il class loader
di A che gestirà l'integrazione e dunque B
e A avranno lo stesso class loader.
Tale disposizione assicura che non ci saranno mai interferenze fra
due applicazioni con due class loader diversi.
Un altro compito del class loader è di assicurare che
all'interno di una applicazione ogni class viene caricata una volta
sola e che le class di base non possono essere sostituite.
Security Manager
Ad un'applicazione si può associare un security manager
che gestisce l'accesso alle risorse del sistema (accesso a un file,
ad un indirizzo Web, alla grafica). Il security manager può
accettare o rifiutare tale accessi. Per esempio, il security manager
dentro il browser rifiuta tutti gli accessi ad un qualsiasi file.
Dunque un'applicazione
proveniente dalla rete non può vedere il contenuto del
disco locale.
Crittografia
Si vorrebbe permettere un accesso meno restrittivo al codice scaricato
dalla rete e proveniente da una persona di fiducia. Per fare ciò
in modo sicuro, bisogna utilizzare la crittografia che consente di
garantire l'identità di una persona. Il meccanismo proposto da
Java è quello di firmare crittograficamente gli oggetti. Quindi
si può permettere, in modo sicuro, un accesso alle risorse locali
da parte degli oggetti che hanno tale firma crittografica.
Laurent Théry
Last modified: Tue Apr 1 23:19:39 MEST 2003