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