Introduzione


Per utilizzare programmi in java già compilati serve la JRE (Java Runtime Environment) che è una implementazione della JVM (Java virtual Machine). Questa applicazione interpreta i bytecode. Per usare un IDE o un applet è necessario avere JRE installato che provvede a lanciare il comando :


java nomefile


Per sviluppare programmi Java è necessario avere la JDK (Java Development Kit) che contiene al suo interno una o più JRE, debuggers, compilatori come javac, librerie o classi per lo sviluppo.

Oss. - esistono due versioni di JDK :

  1. JDK SE (standard edition) : adatto per la maggior parte dei progetti Java;

  2. JDK EE (enterprise edition) : adatto al mondo aziendale, contiene per esempio librerie e applicazioni server (es. Glass Fish Server di Oracle)


Al momento sono disponibili :

E' necessario installare una JDK e impostare una PATH per raggiungere la cartella “bin” dell'installazione. In questo modo si possono utilizzare i seguenti comandi dalla shell o da un terminale (dipende da che S.O. si sta usando) da qualsiasi posizione :

il comando per compilare un file tipo “nomefile.java” è


Javac nomefile.java → nomefile.class


come si vede sopra, verrà creato un ulteriore file omonimo con estensione “.class”. A questo punto per far partire l'applicazione con la JVM è necessario il seguente comando


java nomefile


Installando un ambiente di sviluppo integrato IDE (Integrated Development Environment) (es. Eclipse, NetBeans, etc.), cioè programmi utili al programmatore in quanto permettono lo sviluppo del sorgente scrivendolo mediante l'editor incorporato, di evidenziare errori di sintassi, suggeriscono il completamento delle istruzioni (questo velocizza la programmazione ed evita errori di scrittura) e sono di supporto al debugging. Con questi programmi è necessario solo il JRE per far eseguire i file compilati (bytecode), tutti gli altri strumenti sono già a corredo dei programmi IDE. Usando un IDE non è necessario fare le configurazioni utili per lavorare a righe di comando. Quando si compila, l'IDE chiama il compilatore java (javac) il quale traduce il sorgente scritto con il l'editor in un file bytecode che la JVM è in grado di eseguire. Per eseguire il programma utilizzerà proprio la JVM installata (vedremo nella lezione dedicata).




Variabile : nome assegnato ad un area di memoria. Questo nome prende il nome di identificatore. Quando si dichiara una variabile va specificato il tipo (vedi sotto) di dato che deve contenere, in questo modo il sistema operativo assegna alla variabile uno spazio corretto nella memoria (in pratica il programmatore non si pone il problema di gestire quale locazione di memoria usata). Durante l'esecuzione può assumere molti valori compatibili con il tipo (vedi sotto) assegnato. Per poter fare dei programmi abbiamo bisogno di introdurre il concetto di variabile . Supponiamo che io vi dica di ricordare il numero 5 nella vostra memoria e poi vi dica di ricordare anche il numero 2. Allora voi avrete registrato due valori nella vostra memoria. Ora, se vi chiedo di sommare 1 dal primo numero voi memorizzerete 6 al posto di 5 come primo numero e quindi ricorderete i due valori 6 (5+1) e 2. A questo punto posso chiedervi di fare la differenza tra i due valori e dirmi il risultato : il valore 4. Il processo che avete eseguito è simile a quello che il calcolatore può effettuare usando due variabili. In C++ esso viene descritto dalle istruzioni:

a = 5;
b = 2;
a = a + 1;
risultato = a - b;

Naturalmente questo è un esempio molto semplice che coinvolge soltanto due valori interi molto piccoli, ma un calcolatore può memorizzare milioni di valori ed effettuare operazioni matematiche molto complesse su di essi, il tutto ad una velocità inimmaginabile per una persona. Possiamo quindi definire una variabile come una porzione di memoria in cui memorizzare un valore. Ogni variabile necessita di un identificatore (un nome) che la distingue da ogni altra variabile, ad esempio nel codice precedente gli identificatori sona b risultato , ma avremmo potuto chiamare le variabili con un qualsiasi altro nome inventato da noi, purchè esso sia un identificatore (vedi sotto) valido. I simboli da usare per gli identificatori sono :

termini tecnici dell'informatica legati alle variabili :

int pippo;

questa istruzione si definisce dichiarazione della variabile pippo, il S.O. assegna uno spazio RAM adatto a contenere una variabile tipo int ed chiama quello spazio pippo

pippo = 346;

questa istruzione si definisce assegnazione perché attribuisce un valore alla variabile pippo che il S.O. inserirà nella memoria assegnata alla variabile

int pippo = 123;

questa istruzione si definisce inizializzazione della variabile. Mediante l'operatore di assegnamento “=” oltre a dichiarare la variabile gli assegna direttamente un valore che verrà posto dal S.O. nell'area di memoria assegnata alla variabileDurante

Se una variabile viene usata senza avergli attribuito un valore, viene visualizzato un errore

.. variable i might not have been inizialized …...

Per convenzione si seguono le seguenti regole :

Ci sono precise definizione distinte delle variabili che dipendono dallo scope :

variabile letterale : è la definizione di un numero scritto con le cifre all'interno di un espressione (vedi più avanti cosa si intende per espressione)

variabili locali : sono variabili definite all'interno dei metodi e sono visibili solo nel blocco codice del metodo stesso. All'uscita del metodo mediante l'istruzione return la variabile viene dealloccata. Se viene chiamata una variabile mediante il suo identificatore da un altro metodo viene visualizzato un errore.

Parametri attuali : sono le variabili, il cui valore, viene passato quando si chiama un metodo.

Parametri formali : sono le variabili dichiarate all'interno delle parentesi tonde all'interno della firma del metodo. La visibilità è la stessa delle variabili locali, e anche la deallocazione avviene nell'istante dell'uscita dal metodo.

Scope delle variabili : lo scope è l'area del programma, dipendente dal tipo, in cui un identificatore rimane associato ad un area di memoria.

variabili di istanza : sono le variabili definite anche attributi o campi (field) all'interno della classe ma esterne dai metodi. Il loro scope è l'intero blocco della classe compreso i blocchi dei metodi ivi compresi. Se l'identificatore di una variabile istanza è uguale a quella di una variabile locale o parametro di un metodo, all'interno del metodo viene usato il valore locale o passato al parametro. In caso di omonimia per usare una variabile istanza all'interno di un metodo bisogna usare il qualificatore this (es. this.nomevariabile). Quest'ultimo concetto diventerà più chiaro nella lezione dei metodi.

es.

void pippo(int pluto)

{

int topolino = 1;//dichiara e inizializza variabile

topolino = topolino + pluto; //istruzione che assegna un valore alla var. topolino mediante l'espressione

}

le variabili pippo e topolino vengono assegnate alla RAM (lo spazio di una variabile int) per eseguire la funzione del metodo, e poi spariscono e non possono essere usate nel resto del codice.

Costante : nome assegnato ad un area di memoria. Anche per le costanti il nome è definito identificatore. I nomi assegnati alle variabili sono formati da lettere maiuscole e se formate da più parole queste vengono unite dall'underscore “_”. Anche le costanti devono essere legate a un tipo (vedi sotto). Per rendere una variabile inizializzabile o assegnabile a un valore solo una volta uso il qualificatore final. Se la voglio definire costante globale va inserito il qualificatore static (es. final static PIPPO;)


Identificatore variabili: la convenzione in Java è quella di capitalizzare il nome dalla seconda parola e, nonostante sia possibile, evitare di usare i simboli “_” e “$”. Quindi se la parola è singola è convenzione scriverla tutta in minuscolo (es. primaVariabileJava). Ci sono parole chiave del linguaggio che non possono essere utilizzate come identificatori :


abstract

continue

for

new

switch

assert

default

goto

package

synchronized

boolean

do

if

private

this

break

double

implements

protected

throw

byte

else

import

public

throws

case

enum

instanceof

return

transient

catch

extends

int

short

try

char

final

interface

static

void

class

finally

long

strictfp

volatile

const

float

native

super

while



Tipi : Java è un linguaggio fortemente tipato. Quindi tutte le variabili e le costanti sono tipate, cioè possono contenere un insieme di elementi specifici che dipendono dal tipo assegnato. Il tipo è un termine di classificazione che raggruppa tutte quelle variabili che sono memorizzate nello stesso modo e a cui si applica lo stesso insieme di operazioni.


Tipo

Q.tà di Memoria

Informazione rappresentata

Valore di default

Esempi

a esempi ok

b esempi errati

byte

8 bit

(1 byte)

Variabile con segno (con rappresentazione “two’s complement”, complemento a due) e rappresenta valori in un range [-128 e 127] (estremi inclusi).

Numeri interi

0

byte a = -48;

byte b = 320;

short

16 bit

(2 byte)

Numeri interi (con segno) in un range [-32768, 32767]

0

short a = 31233;

short b = 33000;

int

32 bit

(4 byte)

Numeri interi (per default con segno, signed) in un range [-231, 231-1] . Con Java 8 è stata introdotta la possibilità di utilizzare gli int per rappresentare quantità unsigned che potranno avere range [0, 232-1] (grazie ad appositi metodi statici introdotti nelle classi Integer e Long)

0

int a = 7500000;

int b = 333;

long

64 bit

(8 byte)

Numeri interi (per default con segno, signed) in un range 

[-263, 263-1] o in decimale

[9'223'372'036'854'775’808, 9'223'372'036'854'775’807]. Come per gli interi in Java 8 esiste la possibilità di utilizzarli come quantità unsigned con range (positivo) che arriva fino a264-1.


0L

long a = 933L;

long a = 333L;

long b = 363L;


nota – senza L finale i numeri vengono letti come tipo int.


float

32 bit

(4 byte)

Numeri in virgola mobile in singola precisione secondo la specifica IEEE 754, utilizzando la rappresentazione segno, mantissa esponente. 
(-1)segno * mantissa * 2esponente

Nella versione a 32bit il range rappresentabile va calcolato pensando ad un bit di segno, una mantissa a 23bit e un esponente a 8bit con valori compresi tra -126 e 127.

range

+/-[1.40129846432481707*10-45, 3.40282346638528860*1038]

Inoltre lo standard prevede la rappresentazione di due valori per zero (da destra e da sinistra) due per infinito (positivo e negativo), e di valori NaN (not a number) da utilizzare ad esempio come risultati di operazioni impossibili (es. divisioni per zero, radice a indice pari con radicandi negativi).

0.0f

float a = 765.456F;

float a = 2.876E33;

float a = 234,67;

float b = 2;



nota 1 – E sta per “*10^” per utilizzare la notazione scientifica a base 10.

nota 2 – se non viene messa la F finale, un numero con il “.” è considerato decimale e di default tipo double.

double

64 bit

(8 byte)

Numeri in virgola mobile in doppia precisione secondo la specifica IEEE 754. La precisione con cui vengono rappresentati i numeri aumenta in virtù dell’aumento del numero di bit utilizzati. Il range

+/-[4.94065645841246544*10-324, 1.79769313486231570*10308]

0.0d

double a = 12345678,9876;

boolean

sarebbe sufficiente un solo bit

serve a rappresentare solamente 2 valori: vero o falso (true o false).

false

boolean a = (5>3);//true

boolean b = (5<3);//false

char

16 bit (2 byte)

È utilizzato per la memorizzazione di caratteri del charset Unicode nel range ['\u0000', '\uffff'] (in esadecimale) o equivalentemente[0,65535].

\u0000

Char a = 'c';

char b = “g”;

char b = g;

void

---

Equivale a “nessun tipo”

usato nei metodi che non restituiscono valori. Questo dimostra che è intenzione del programmatore non restituire un valore



String

---

Non è un tipo primitivo ma una classe usata per le stringhe alfanumeriche. Quindi si possono gestire mediante i metodi della classe (vedremo tutto in una lezione dedicata).


String a = “ciao”;

String a = “1234”;

String b = pippo;

Nota – nei tipi che rappresentano i valori reali (float e double) si segue lo standard IEEE754 che oltre che rappresentare i numeri positivi e negativi ha anche dei valori particolari :



Nel tipo char o String (non è un tipo primitivo ma una classe e permette di gestire stringhe con più elementi) ci sono anche i caratteri Escape


Escape

Carattere

\b

backspace (indietro)

\t

tab

\n

line feed (fine linea)

\f

form feed (fine pagina / nuova pagina)

\r

carriage return (ritorno carrello / a capo)

\’

apice singolo

\”

doppio apice

\\

backslash (\)



Nota - per altre informazioni sul tipo String (o meglio alla classe String) vedremo una lezione dedicata.



Espressioni : insieme di variabili e numeri concatenati con gli operatori aritmetici binari: +, -, *, / , % (resto della divisione intera) e quelli unari ++ (incremento) - - (decremento).

es.

(a+25)/b


Ciascun operatore gestisce dati omogenei, ma sommando per esempio un tipo int con un tipo short, java converte tutto in int. Questo effetto automatico viene chiamato promozione numerica. Lo stesso procedimento accadrebbe con le seguenti istruzioni :


int a = 5;

long b = a;


la conversione di “a” è automatica. Ma se invertiamo l'ordine delle istruzioni


long a = 5L;

int b = a;


in questo caso il compilatore emette un warning, perché c'è il rischio di perdere dell'informazione nel valore di a se è troppo elevato. Java chiede che il programmatore sia certo di questa operazione. Il modo per far capire al compilatore che il programmatore è consapevole è l'uso del casting :


casting implicito : la JVM interpreta i dati e definisce la conversione

casting esplicito : definisce il tipo del risultato, in questo modo si dimostra alla JVM che abbiamo deciso responsabilmente la conversione


variabile = (tipo in cui convertire) espressione;


come esempi pratici di quanto detto :


long a = 5L;

int b = (int)a;


prima di effettuare la seconda istruzione, la variabile a viene convertita in tipo int. Il casting è applicabile solo tra tipi compatibili : short, int, long, float e double. Non è possibile usare un casting tra un tipo bool e un char o altro esempio tra un String e un numero. Un'altra situazione in cui Java esegue un casting implicito è la seguente


System.out.println(8/3); //risultato 2, quindi risultato tipo int


ovviamente è errato, ma essendo i due valori interi, anche il risulato è intero. Un modo per influenzare il risultato puo essere quella di moltiplicare per 1.0 (notare l'uso del punto tipico anglosassone, la virgola viene usata per separare più parametri).


System.out.println(1.0*8/3); //risultato 2.66666... quindi il casting implicito converte in double


quando si usa questa tecnica bisogna prestare attenzione alla priorità degli operatori.


operatori postfissi

[] . (paramsexpr++ expr--

operatori unari

++expr --expr +expr -expr !

instanze e cast

new (type)expr

aritmetici

* / %

aritmetici

+ -

di relazione

< > <= >=

uguaglianza

== !=

AND

&&

OR

||

condizionale

? :

assegnamento

= += -= *= /= %= &= |=

Quando nella stessa espressione appaiono operatori con la stessa precedenza occorre stabilire quale viene valutato prima. Gli operatori binari sono valutati da sinistra a destra, mentre gli assegnamenti sono valutati da destra a sinistra. Ovvio che l'uso delle parentesi cambia l'ordine, le parentesi interne sono calcolate con priorità rispetto alle altre.


Quindi l'espressione


System.out.println(6/3*1.0);risultato 2.0


il risultato è dovuto al fatto che l'ordine di esecuzione (vedi tabella e note sopra) è 6/3 = 2 e 2*1.0 = 2.0 perché viene applicato il casting implicito. Per applicare invece il casting implicito si usa il metodo visto sopra


System.out.println((int) (6/3*1.0));risultato 2


nelle espressioni normali Java richiede di usare il casting esplicito. Come parametri si può sfruttare quanto sopra, nelle espressioni il sistema Java richiede l'uso del casting esplicito.


Le espressioni aritmetiche pi`u semplici sono costituite da singoli letterali


Letterali interi: 3425, 12, -34, 0, -4, 34, -1234, ....


Letterali frazionari: 3.4, 5.2, -0.1, 0.0, -12.45, 1235.3423, ....


Espressioni più complesse si ottengono utilizzando operatori aritmetici : moltiplicazione *

divisione /

modulo % (resto della divisione tra interi)

addizione +

sottrazione -


Le operazioni sono elencate in ordine decrescente di priorità ossia


3+2*5


fa 13 non 25. Le parentesi tonde cambiano l’ordine di valutazione degli operatori ossia (3+2)*5 fa 25. Inoltre, tutti gli operatori sono associativi a sinistra ossia 3+2+5 corrisponde a (3+2)+5 quindi 18/6/3 fa 1.


L’operazione di divisione / si comporta diversamente a seconda che sia applicato a letterali interi o frazionari


25/2 = 12 (divisione intera)

25%2 = 1 (resto della divisione intera)

25.0/2.0 = 12.5 (divisione reale)

25.0%2.0 = 1.0 (resto della divisione intera)

Una operazione tra un letterale intero e un frazionario viene eseguita come tra due frazionari 25/2.0 = 12.5 1.5 + (25/2) = 13.5 (attenzione all’ordine di esecuzione delle operazioni) 2 + (25.0/2.0) = 14.5


Spesso però può essere utile convertire una stringa formata da cifre numeriche in un numero. Questo è utile anche perche, come vedremo, i valori inseriti da tastiera sono letti come tipo String, quindi per usare un numero inserito, all'interno di un espressione, devo convertirlo. Per ogni tipo numerico esiste una classe che ne rappresenta il tipo, il nome delle classi equivale al nome del tipo ma con l'iniziale maiuscola (cambia solo per int) : Byte, Short, Integer, Long, Float, Double. Le classi sono contenute nel package java.lang . I metodi da usare sono i seguenti :


parseByte()

parseShort()

parseInteger()

parseLong()

parseFloat()

parseDouble()


es.

String numstr = “234.567”

double numdouble = parseDouble(numstr); // numdouble == 234.567


Nel caso di inserimento da tastiera, se sono presenti simboli non numerici, nel caso di conversione viene generato un errore che impareremo a gestire più avanti nel corso. Un errore viene generato anche nel caso in cui la conversione venga fatta da una stringa che contiene un valore troppo grande rispetto al range del tipo convertito.


Ricordando che i numeri int e long possono essere scritti in binario e esadecimale :

0xA9

0b01010111

Ci sono gli operatori che lavorano sui singoli bit

Operatore

Operazione logica

~ (tilde)

NOT

&

AND

|

OR

^

XOR

<<

Scorrimento bit a sinistra

es.

byte a = 4; 00000100

System.out.print(a << 3);

// 00100000 ris. 32

>>

Scorrimento bit a destra

>>>

Scorrimento bit a destra senza segno

Tilde su Windows e Linux - L'operatore binario NOT è rappresentato con il simbolo ~, chiamato tilde. Non è un carattere che si trova sulle tastiere italiane. Pertanto, per digitarlo, è necessario ricorrere ad una particolare combinazione.


Windows sui PC e portatili con tastierino numerico

 ALT + 126

Windows sui portatili privi di tastierino numerico:

ALT + Fn + 126

Linux

ALT Gr + ì

nel terminale di Linux:

PG DOWN
Mac OS X
Alt + 5


Poi ci sono gli operatori di confronto (<, >, !=, ==, <=, >=)


Simbolo

descrizione

=

assegnazione

==

Uguaglianza

!=

Differenza

>

Maggiore

>=

Maggiore/uguale

<

Minore

<=

Minore/uguale

+=

Aggiunge alla variabile del primo membro il valore secondo membro

-=

Toglie alla variabile del primo membro il valore secondo membro

&&

And logico tra le due espressioni (exp==0 false, exp>0 true)

||

Or logico tra le due espressioni (exp==0 false, exp>0 true)



Istruzioni o comandi : utilizza i simboli di confronto (<, >, !=, ==, <=, >=) o assegnazione (=) con una variabile o parole chiave che compiono un operazione. Termina con un “;” (senza virgolette). L'elenco delle istruzioni racchiuse tra parentesi graffe è definito blocco istruzioni (statement).

es.

c = (a+25)/b;


CLASSI


vedi lezione dedicata


METODI


vedi lezione dedicata



OGGETTI



vedi lezione dedicata