Caricare documenti e articoli online 
INFtub.com è un sito progettato per cercare i documenti in vari tipi di file e il caricamento di articoli online.


 
Non ricordi la password?  ››  Iscriviti gratis
 

Il linguaggio JAVA - Introduzione al linguaggio java

informatica




Il linguaggio JAVA


Introduzione al linguaggio java

Java è un linguaggio orientato agli oggetti indipendente dalla piattaforma grazie all'uso della Java Virtual Machine che traduce le istruzioni dei codici binari indipendenti dalla piattaforma, generati dal compilatore java, in istruzioni eseguibili dalla macchina locale.


Caratteristiche principali

Grazie alla JVM un'applicazione java può essere eseguita su qualunque piattaforma senza dover essere ricompilata.

Gestisce l'uso della memoria grazie ad un meccanismo detto Garbage Collector che tiene traccia degli oggetti utilizzati da un'applicazione java e ogni volta che uno di essi non è più referenziato lo rimuove dalla memoria liberando la risorsa occupata. Non è in grado di gestire casi di referenza circolare.



E' un linguaggio multi-threaded, ciò permette che parti separate di un programma possano essere eseguite come se fossero processate parallelamente.

Supporta il metodo Dynamic Loading and Linking secondo il quale ogni modulo del programma (classe) è memorizzato in un determinato file. In questo modo quando un programma java viene eseguito le classi vengono caricate e stanziate solo al momento del loro effettivo utilizzo.


Introduzione alla sintassi java

-) Modificatore FINAL => serve per definire costanti.

final identificatore var_name = var_value.


-) Definizione di una CLASSE. Una classe deve rappresentare un oggetto concettuale.

class ObjectName



I dati e i metodi contenuti nella classe sono detti MEMBRI della classe e devono essere rigorosamente definiti all'interno della classe stessa.


-) Variabili reference

Java fa una netta distinzione tra dati primitivi (INT) e classi (STACK); in particolare un oggetto (classe) non è allocato dal linguaggio al momento della dichiarazione mentre un dato primitivo si. Nel caso di dichiarazione di un oggetto viene creata una variabile che referenzia l'oggetto senza che venga allocato in memoria. Anche gli array in java non vengono allocati al momento della dichiarazione.


Tipo primitivo => INT counter; => vengono allocati 4 byte per contenere un intero.

Oggetto => STACK s; => vengono allocati 4 byte per referenziare un oggetto di tipo STACK futuro. 848d31i

Array => INT numbers[]; => vengono allocati 4 byte per referenziare un array di interi futuro.


-) L'oggetto NULL

Il valore speciale NULL rappresenta un oggetto inesistente. Una variabile reference uguagliata NULL sta ad indicare che tale variabile non referenzia momentaneamente nessun oggetto. Bisogna ben ricordare che NULL non equivale a 0 (come in C e C++).

Stack s = NULL;





-) Creare istanze

Per creare l'istanza di un nuovo oggetto o di un array java mette a disposizione l'operatore NEW che alloca la memoria necessaria per l'oggetto, o array, e restituisce la locazione alla variabile reference che lo referenzia.


Classe => NEW class_type );

Oggetto Stack => Stack s = NEW Stack();

Array => int Numbers[] = NEW int[20];


-) Operatore punto

Questo operatore è usato per accedere ai membri di un oggetto tramite la variabile reference.

s.push(Stack_el);

Con questa riga chiamiamo il metodo push dell'oggetto referenziato da s passandogli il parametro Stack_el.


-) Auto referenza esplicita

Java prevede una modalità di referenziazione speciale identificata da THIS. Il valore di THIS viene modificato automaticamente da java in modo che ad ogni istante sia sempre referenziato all'oggetto attivo,cioè all'istanza dell'oggetto in esecuzione durante la chiamata al metodo corrente.


-) Auto referenza implicita

Dato che la visibilità di una variabile in java è limitata al blocco di codice in cui è stata fatta la dichiarazione, java basa su questo meccanismo la auto referenza implicita. Java ricerca una variabile non qualificata risalendo a ritroso tra i diversi livelli dei blocchi di codice. Se la variabile non è un dato membro dell'oggetto verrà generato un codice d'errore.


-) Stringhe

Le stringhe in java sono oggetti che possono essere inizializzati semplicemente senza utilizzare l'operatore new.

STRING parola = "Ciao"

Per concatenare due stringhe è sufficiente utilizzare l'operatore di addizione. Le stringhe, inoltre, hanno un membro che ritorna la lunghezza della stessa che è LENGHT():

INT lunghezza = parola.lenght();


-) Comparazione di oggetti

Per verificare che due oggetti siano uguali dobbiamo verificare che entrambi si trovino nello stesso stato al momento del confronto. Dato che non è possibile utilizzare l'elemento ==, dato che comparerebbe il riferimento e non lo stato dell'oggetto, java mette a disposizione un metodo speciale chiamato EQUALS() che confronta, appunto, lo stato di due oggetti.


Stack a = new Stack();

Stack b = new Stack();

a.push(1);

b.push(1);

a.equals(b); => in questo caso restituisce TRUE.


-) Metodi statici

Un metodo statico è un metodo che appartiene a una classe e che non richiede l'attività da parte dell'oggetto di cui è membro. Un metodo statico esiste sempre a prescindere dallo stato dell'oggetto. Per rendere un metodo statico si utilizza la parola chiave STATIC.

STATIC INT static_method


L'Oggetto System

E' una classe predefinita di java che fornisce una serie di metodi statici e rappresenta il sistema su cui l'applicazione java sta girando. Per citarne alcuni:

System.out.println("Ciao");

System.err.println("Errore");

System.exit();

Controllo di flusso e distribuzione di oggetti

-) I Package

I package java sono strumenti simili a librerie e servono come meccanismo per raggruppare classi o distribuire oggetti. L'istruzione IMPORT è un'istruzione speciale utilizzata dal compilatore per determinare la posizione su disco delle definizioni di classi da utilizzare nell'applicazione corrente.


import app.stack.Stack;

import app.stack.*;


I benefici apportati dall'uso dei package sono:


  1. Le classi possono essere mascherate all'interno dei package implementando l'incapsulamento anche a livello di file.
  2. Le classi di un package possono condividere dati e metodi con classi di altri package.
  3. I package forniscono un meccanismo efficace per distribuire oggetti.

Una volta definito il nome di un package (diverso da java), affinché una classe possa essere archiviata al suo interno, è necessario aggiungere una istruzione package all'inizio del codice sorgente che definisce la classe.


package Nome_package (package app.stack)


-) Il modificatore PUBLIC

Questo modificatore permette di esplicitare quali classi e quali membri possano essere utilizzati all'esterno del package. Di default la definizione di una classe java può essere utilizzata solo dalle classi all'interno del suo stesso package. le specifiche del linguaggio richiedono che il codice sorgente di classe pubblica sia memorizzato in un file avente lo stesso nome della classe, ma con estensione ".java".


-) Le istruzioni di ramificazione

Queste istruzioni sono tre:

  • BREAK => interrompe l'esecuzione di un ciclo evitando ulteriori controlli sull'espressione condizionale e ritorna il controllo all'istruzione successiva al blocco attuale.
  • CONTINUE => salta un blocco di istruzioni all'interno di un ciclo e ritorna il controllo all'espressione booleana che en governa l'esecuzione.
  • RETURN => interrompe l'esecuzione del metodo attuale e ritorna il controllo al metodo chiamante.

Incapsulamento

L'incapsulamento di oggetti è il processo di mascheramento dei dettagli dell'implementazione ad altri oggetti per assicurare all'utente che ciò che sta utilizzando è sempre in uno stato consistente, cioè permesso.


-) Modificatori PUBLIC, PRIVATE e PROTECTED

  • I membri di una classe definiti PUBLIC sono liberamente accessibili da ogni classe utilizzata nell'applicazione. Questo modificatore è tipicamente utilizzato per definire l'interfaccia che l'oggetto mette a disposizione dell'utente.
  • I membri di una classe definiti PRIVATE possono essere utilizzati solo dai membri della stessa classe, per mascherare porzioni di codice della classe che non devono essere utilizzati da altre classi.
  • I membri di una classe definiti PROTECTED possono essere utilizzati sia dai membri della stessa classe che da altre classi purché appartenenti allo stesso package.

-) I COSTRUTTORI

I COSTRUTTORI sono metodi speciali chiamati quando viene creata una nuova istanza di classe e servono a inizializzare lo stato iniziale dell'oggetto. Essi hanno lo stesso nome della classe di cui sono membro e non restituiscono nessun tipo. E' consentito scrivere più di un costruttore per una data classe a seconda delle necessità di disegno dell'oggetto, permettendogli di passare diversi insiemi di dati di inizializzazione (OVERLOADING dei costruttori). Per ridurre la quantità di codice, java permette di chiamare un costruttore da un altro utilizzando la sintassi:


THIS(lista_parametri)


dove per lista-parametri si intende la lista dei parametri del costruttore che si intende chiamare. Questa chiamata definita CROSS-CALL deve essere la prima riga di codice del costruttore chiamante.


L'ereditarietà

L'EREDITARIETA' è la caratteristica che consente di utilizzare classi come base per la definizione di nuovi oggetti che ne specializzano il concetto: i membri della classe base sono concettualmente copiati nella nuova classe. Alla nuova classe e concesso di modificare i metodi ereditati e di aggiungerne di nuovi. Tutto ciò mantenendo protetta la super-classe da eventuali nuovi bug. Java consente di poter ereditare da una sola classe base (EREDITARIETA' SINGOLA). L'estensione di una super-classe in una classe generica è possibile tramite il modificatore EXTEND:

CLASS Nome_Classe EXTEND Nome_Super_Classe


-) OVERLOAD dei metodi

Eseguire l'overloading di un metodo significa dotare una classe di metodi aventi stesso nome ma con parametri differenti. Esistono alcune regole d'uso dell'overloading:


  • non possono esistere due metodi aventi nome e lista dei parametri contemporaneamente uguali.
  • i metodi di cui si è fatto l'overloading devono implementare vari aspetti di una medesima funzionalità.

-) Ereditarietà e incapsulamento

L'effetto dei modificatori public, private e protected nell'ereditarietà sono:


  • Il modificatore PUBLIC consente di dichiarare dati e metodi membro visibili e quindi utilizzabili da un'eventuale sottoclasse.
  • Il modificatore PRIVATE nasconde completamente dati e metodi membro dichiarati tali.
  • Il modificatore PROTECTED consente l'accesso a un metodo o dato membro di una classe e tutte le sue sottoclassi o alle classi appartenenti allo stesso package. In tutti gli altri casi non sarà possibile utilizzare metodi e dati membro definiti protetti.

-) Ereditarietà e costruttori

Per quanto riguarda l'utilizzo dei costruttori java introduce due regole base:


Ogni classe deve avere un costruttore. Se il programmatore non lo implementa ne viene assegnato uno di default.

Se una classe è derivata da un'altra l'utente può chiamare il costruttore della classe base usando l'istruzione:


SUPER(Lista_argomenti)


-) OVERRIDING dei metodi

Se un metodo ereditato non lavorasse correttamente rispetto a quanto ci aspettiamo java ci consente di riscrivere il metodo originale. Riscrivendo nuovamente il metodo nella nuova classe, non c'è pericolo che la classe base venga manomessa. Il nuovo metodo verrà chiamato al posto del vecchio.

La parola chiave SUPER può essere usata anche nel caso sia necessario richiamare un metodo della super-classe ridefinito, con l'overriding, nella classe derivata.


-) Flessibilità delle variabili reference

Una volta che una classe java è stata derivata java consente alle variabili reference che rappresentano il tipo della classe base di referenziare ogni istanza di un oggetto derivato da essa. Il motivo alla base di questa funzionalità è che tutti gli oggetti derivati hanno sicuramente almeno tutti i metodi della classe base. Supponendo di avere una classe base Persona e una classe ereditata Studente la flessibilità delle variabile reference ci permette di:

Persona p = NEW Studente();

p.studia();  // Metodo studia() dichiarato nella classe Studente

Vedremo in seguito che la chiamata precedente non è corretta.


-) Run-time e Compile-time

Il tipo rappresentato a compile-time di un'espressione è il tipo dell'espressione come dichiarato formalmente nel codice sorgente. Il tipo rappresentato a run-time è quello determinato quando il programma è in esecuzione. Il tipo a compile-time è sempre costante mentre quello a run-time può variare. Nell'esempio di prima una variabile reference di tipo Persona rappresentava il tipo Persona a compile-time, e il tipo Studente a run-time.


-) CAST dei tipi

Il cast di un tipo consente di dichiarare che una variabile reference temporaneamente rappresenterà un tipo differente da quello rappresentato al compile-time nel seguente modo:

(Nuovo_tipo) Variabile;

Un esempio di cast è il seguente:

Studente s = NEW Studente );

Persona p = s;

s.studia();

p.studia();   // Chiamata errata

((Studente) p).studia();    // Chiamata corretta


-) L'operatore INSTANCEOF

L'operatore instanceof controlla il tipo di oggetto referenziato al run-time da una variabile reference e funziona in questo modo:

A INSTANCEOF B

Dove A rappresenta una variabile reference e B un tipo referenziabile. Il tipo rappresentato al run-time dalla variabile reference A verrà confrontato con il tipo definito da B. L'operatore tornerà il valore TRUE se il confronto darà esisto positivo, FALSE altrimenti.


Polimorfismo e ereditarietà avanzata

-) Polimorfismo:"un'interfaccia molti metodi"

Il polimorfismo è una caratteristica della programmazione a oggetti che ci permette di utilizzare un'interfaccia per una moltitudine di azioni. Possiamo definire cioè un'interfaccia unica da utilizzare in molti casi collegati logicamente tra loro. La sintassi di implementazione di un'INTERFACCIA è la seguente:

INTERFACE Identificatore


Per far si che un'interfaccia venga utilizzata è necessario che ne esista un'implementazione. Per implementare un'interfaccia java mette a disposizione la parole chiave IMPLEMENTS, da utilizzare nel seguente modo:

CLASS Nome_classe IMPLEMENTS interface



-) Ereditarietà multipla in java

L'operatore implements prima introdotto ci consente di implementare una classe a partire da quante interfacce desideriamo, esplicitandone l'elenco, in questo modo:

CLASS Nome_classe IMPLEMENTS interface1, interface2, interface3


-) Classi ASTRATTE

Le classi base astratte sono classi solo parzialmente implementate. Per definire una classe astratta java mette a disposizione la parola chiave ABSTRACT; questa clausola informa il compilatore che alcuni metodi della classe potrebbero essere semplicemente prototipi o astratti. Quindi ogni metodo che rappresenta semplicemente un prototipo deve essere dichiarato abstract. Quando una nuova classe viene derivata a partire dalla classe astratta, il compilatore richiede che tutti i metodi astratti vengano definiti, o ridichiarati astratti. Esempio:


ABSTRACT CLASS Nome_classe



Eccezioni

Le eccezioni sono utilizzate da java in quelle situazioni in cui sia necessario gestire condizioni anomale. Formalmente un'eccezione è un evento che si scatena durante l'esecuzione di un programma causando l'interruzione del normale flusso di esecuzione dell'applicazione. Le situazioni di errore possono svilupparsi in seguito a una grande varietà di situazioni anomale:


  • malfunzionamento fisico di un dispositivo,
  • mancata inizializzazione di oggetti particolari,
  • errori di programmazione.

-) Propagazione di oggetti

Il punto di forza del meccanismo delle eccezioni consiste nel consentire la PROPAGAZIONE di un oggetto a ritroso, attraverso la sequenza corrente di chiamate tra metodi. Ogni metodo può fermare la propagazione e gestire la condizione di errore, usando le informazioni trasportate, oppure continuare la propagazione ai metodi subito adiacenti nella sequenza di chiamate. Nel secondo caso il metodo viene interrotto nel punto in cui aveva chiamato il metodo che sta propagando l'errore. Per quanto riguarda l'eccezione una volta propagata essa deve essere intercettata e gestita; in caso contrario essa si propagherà fino al metodo main() causando la terminazione dell'applicazione. Propagare un oggetto è detto EXCEPTION THROWING  e fermare la propagazione EXCEPTION CATCHING. In generale gli oggetti da propagare come eccezioni devono derivare dalla classe base java.lang.Exception.


-) Oggetti THROWABLE

La classe throwable contiene dei metodi necessari a gestire lo STACK TRACING per la propagazione dell'oggetto a ritroso lungo la sequenza corrente delle chiamate. Java richiede quindi che tutti gli oggetti da propagare siano derivati da java.lang.Throwable. Oltre ai costruttori Throwable() e Throwable(String) in questa classe hanno particolare importanza i metodi:


  • public Throwable fillInStackTrace() => registra lo stato dello stack di sistema.
  • public void printStackTrace() => consente di stampare sullo standard error la sequenza restituita dal metodo precedente.

Per convenzione ogni eccezione deve derivare da java.lang.Exception che a sua volta deriva dalla classe Throwable.


-) NullPointerException

Questa eccezione è la più comune tra tutte le eccezioni e viene generata tutte le volte che un'applicazione tenti di fare uso di un oggetto nullo, in particolare se si:


  • Effettua una chiamata ad un metodo di un oggetto nullo.
  • Accede o modifica un dato membro di un oggetto nullo.
  • Richiede la lunghezza di un array nullo.
  • Accede o modifica un campo di un array nullo.
  • Propaga un'eccezione nulla.



-) L'istruzione THROW

Le eccezioni vengono propagate a ritroso tramite questa istruzione che ha sintassi:


THROW Object_instance;

dove Object_instance è un'istanza creata mediante l'operatore new. Questo metodo causa la terminazione del metodo corrente ed invia l'oggetto specificato al metodo chiamante.


-) La clausola THROWS

La clausola throws indica al metodo chiamante che un oggetto eccezione potrebbe essere generato o propagato dal metodo chiamato. Questa clausola ha sintassi:

Return_Type_Method_Name (Param_List) THROWS Throwable_Type


Un metodo che presenta la clausola throws può generare un oggetto di tipo Throwable oppure ogni tipo derivato da esso.


-) Istruzioni TRY / CATCH / FINALLY

Queste due istruzioni fanno parte delle cosiddette ISTRUZIONI GUARDIANE, cioè istruzione deputate alla gestione delle eccezioni. L'istruzione CATCH ha il compito di catturare l'oggetto propagato prima che esso raggiunga l'entry-point del programma. Per far ciò questa istruzione deve essere accompagnata da un blocco TRY che viene utilizzato come guardiano per il controllo di un blocco di istruzioni, potenziali sorgenti di eccezioni. L'istruzione catch cattura solamente le eccezioni di tipo compatibile con il suo argomento e generate dalle chiamate a metodi racchiuse all'interno del blocco try. Se un'istruzione del blocco try genera un'eccezione le rimanenti istruzioni del blocco non vengono eseguite. Di seguito ad ogni blocco catch può essere usato opzionalmente un blocco FINALLY che sarà sempre eseguito prima di uscire dal blocco try/catch. Questo blocco fornisce ad un metodo la possibilità di eseguire sempre un certo insieme di istruzioni a prescindere da come il metodo manipola le eccezioni. I blocchi finally non possono essere evitati dal controllo di flusso dell'applicazione (break, continue, return) e l'unico modo per evitare l'esecuzione di questo blocco di istruzioni è una chiamata di tipo System.exit. La sintassi è la seguente:

TRY

CATCH(Exception var1)

CATCH(Exception var2)

FINALLY


Java threads

Java, come detto in precedenza, è un linguaggio multi-threads. Dal punto di vista dell'utente i threads logici appaiono come una serie di processi che eseguono parallelamente le loro funzioni. Dal punto di vista dell'applicazione rappresentano una serie di processi logici che da una parte condividono la stessa memoria dell'applicazione che li a creati , dall'altra concorrono con il processo principale al meccanismo di assegnazione della CPU del computer su cui l'applicazione sta girando. In java esistono molti thread che vengono avviati dalla JVM tra cui:


Thread per la gestione delle interfacce grafiche.

Il Garbage Collection.

Il metodo main().


-) La classe java.lang.Thread e l'interfaccia RUNNABLE

In java un modo per definire un oggetto thread è quello di utilizzare l'ereditarietà derivando il nuovo oggetto dalla classe java.lang.Thread. Questa classe è fornita dei metodi necessari all'esecuzione, gestione e interruzione di un thread, tra cui:


  • RUN() => utilizzato per implementare le funzionalità eseguite thread.
  • START() => causa l'esecuzione del thread.
  • DESTROY() => distrugge il thread e rilascia le risorse allocate.

Un alternativa a questo metodo di definizione dei threads è quello di utilizzare l'interfaccia RUNNABLE di java.lang che contiene il prototipo di un solo metodo, necessario ad indicare l'entry-point del nuovo thread:


public interface RUNNABLE



-) Sincronizzare thread

Quando due o più thread possono eccedere ad un oggetto contemporaneamente per modificarlo, il rischio a cui si va incontro è quello della corruzione dei dati rappresentati dall'oggetto. Per questo è necessario che i due o più thread vengano sincronizzati ovvero che mentre uno esegue l'operazione l'altro/i deve rimanere in attesa. Java fornisce un metodo per gestire la sincronizzazione mediante la parola chiave SYNCHRONIZED, che deve essere aggiunta ala dichiarazione del metodo. I metodi di questo tipo sono detti THREAD SAFE.


-) Lock

La sincronizzazione dei thread, appena vista, non è in grado di gestire situazioni di deadlock. Jva gestisce questa situazione nel seguente modo: quando un thread entra all'interno di un metodo sincronizzato ottiene il lock sull'istanza dell'oggetto. Il thread che ha ottenuto il lock sull'istanza potrà quindi chiamare altri metodi sincronizzati senza entrare in deadlock. Ogni altro thread che proverà ad utilizzare l'istanza in lock dell'oggetto si metterà in coda in attesa di essere risvegliato al momento del rilascio dell'istanza da parte del thread proprietario. Quando il primo thread avrà terminato le sue operazioni, il secondo otterrà il lock e di conseguenza l'uso privato dell'oggetto. Nel caso in cui un thread effettui una chiamata ad un metodo statico sincronizzato, non potendo ottenere il lock sull'istanza dell'oggetto, ottiene il lock su classe, ovvero su tutte le istanze della classe del metodo che ha chiamato.


-) Blocchi sincronizzati

Alcune volte può essere comodo ottenere il lock su un'istanza direttamente all'interno di un metodo e ristretto al tempo necessario per eseguire solo alcune istruzioni del codice. Java gestisce questa situazione utilizzando blocchi di codice sincronizzati:


public void a (QualcheOggetto una_istanza)














Privacy




Articolo informazione


Hits: 2382
Apprezzato: scheda appunto

Commentare questo articolo:

Non sei registrato
Devi essere registrato per commentare

ISCRIVITI



Copiare il codice

nella pagina web del tuo sito.


Copyright InfTub.com 2024